package com.iwhalecloud.bss.kite.cucc.service.pos.handler.impl;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.iwhalecloud.bss.kite.client.dto.spec.in.ContractOfferDetailDTO;
import com.iwhalecloud.bss.kite.common.constant.KeyConsts;
import com.iwhalecloud.bss.kite.common.constant.ServiceOfferConsts;
import com.iwhalecloud.bss.kite.common.constant.SymbolConsts;
import com.iwhalecloud.bss.kite.common.util.KiteBeanUtils;
import com.iwhalecloud.bss.kite.common.util.KiteDateUtils;
import com.iwhalecloud.bss.kite.common.util.KiteListUtils;
import com.iwhalecloud.bss.kite.common.util.KiteMapUtils;
import com.iwhalecloud.bss.kite.common.util.KiteObjectUtils;
import com.iwhalecloud.bss.kite.common.util.KiteStringUtils;
import com.iwhalecloud.bss.kite.cucc.client.api.goods.IGoodsService;
import com.iwhalecloud.bss.kite.cucc.client.dto.cust.CuccContextCustDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosAccountDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosAttrDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosGoodsDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosGoodsFeeDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosGoodsPayRealtionDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosOrderDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosPaymentDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosProductDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosUserDTO;
import com.iwhalecloud.bss.kite.cucc.common.constant.LocalDcPublicConsts;
import com.iwhalecloud.bss.kite.cucc.common.constant.LocalKeyConsts;
import com.iwhalecloud.bss.kite.cucc.common.constant.LocalServiceOfferConsts;
import com.iwhalecloud.bss.kite.cucc.common.util.CommonUtil;
import com.iwhalecloud.bss.kite.cucc.common.util.DateFormatUtils;
import com.iwhalecloud.bss.kite.cucc.common.util.DateUtils;
import com.iwhalecloud.bss.kite.cucc.dataservice.cache.ExtOrderInfoCache;
import com.iwhalecloud.bss.kite.cucc.dataservice.cache.ResaleOrderInfoCache;
import com.iwhalecloud.bss.kite.cucc.service.attr.LocalAttrHelper;
import com.iwhalecloud.bss.kite.cucc.service.attr.LocalQuerySeqHelper;
import com.iwhalecloud.bss.kite.cucc.service.attr.handler.LocalCityPlaceAttrHandler;
import com.iwhalecloud.bss.kite.cucc.service.batch.BatchAcceptUtil;
import com.iwhalecloud.bss.kite.cucc.service.pay.PaymentService;
import com.iwhalecloud.bss.kite.cucc.service.pos.handler.CuccPosServiceUtils;
import com.iwhalecloud.bss.kite.cucc.service.pos.handler.IKitePosSceneHandler;
import com.iwhalecloud.bss.kite.cucc.service.pos.handler.KitePosHandlerContext;
import com.iwhalecloud.bss.kite.cucc.service.util.ChangeTypeUtils;
import com.iwhalecloud.bss.kite.cucc.service.util.ProdCateUtil;
import com.iwhalecloud.bss.kite.cucc.spec.impl.transfer.GoodsInfoTransfer;
import com.iwhalecloud.bss.kite.dataservice.cache.DcPublicCache;
import com.iwhalecloud.bss.kite.dataservice.cache.DcSystemParamCache;
import com.iwhalecloud.bss.kite.dataservice.cache.OfferCache;
import com.iwhalecloud.bss.kite.dataservice.cache.ProdAttrCache;
import com.iwhalecloud.bss.kite.dataservice.cache.ProdFeeCache;
import com.iwhalecloud.bss.kite.dataservice.cache.ProdRelCache;
import com.iwhalecloud.bss.kite.dataservice.cache.ProductCache;
import com.iwhalecloud.bss.kite.dataservice.cache.ServiceControlScopeCache;
import com.iwhalecloud.bss.kite.dataservice.entity.DcPublic;
import com.iwhalecloud.bss.kite.dataservice.entity.ServiceControlScope;
import com.iwhalecloud.bss.kite.dataservice.entity.spec.Offer;
import com.iwhalecloud.bss.kite.dataservice.entity.spec.OfferDetail;
import com.iwhalecloud.bss.kite.dataservice.entity.spec.OfferRelInfo;
import com.iwhalecloud.bss.kite.dataservice.entity.spec.ProdAttr;
import com.iwhalecloud.bss.kite.dataservice.entity.spec.ProdRelInfo;
import com.iwhalecloud.bss.kite.dataservice.entity.spec.Product;
import com.iwhalecloud.bss.kite.dataservice.util.GeneralSwitchUtils;
import com.iwhalecloud.bss.kite.dataservice.util.IdUtils;
import com.iwhalecloud.bss.kite.manager.api.IOperateSceneInstService;
import com.iwhalecloud.bss.kite.manager.api.IQuerySceneInstService;
import com.iwhalecloud.bss.kite.manager.dto.KiteInstDTO;
import com.iwhalecloud.bss.kite.manager.dto.KiteInstRelDTO;
import com.iwhalecloud.bss.kite.manager.enums.ActionType;
import com.iwhalecloud.bss.kite.manager.enums.InstType;
import com.iwhalecloud.bss.kite.manager.enums.RelType;
import com.iwhalecloud.bss.kite.manager.inst.KiteAttr;
import com.iwhalecloud.bss.kite.manager.inst.KiteAttrValue;
import com.iwhalecloud.bss.kite.manager.inst.KiteInst;
import com.iwhalecloud.bss.kite.manager.inst.KiteOfferInst;
import com.iwhalecloud.bss.kite.manager.inst.KiteOfferInstAcct;
import com.iwhalecloud.bss.kite.manager.inst.KiteOfferInstContract;
import com.iwhalecloud.bss.kite.manager.inst.KiteOfferInstDiscount;
import com.iwhalecloud.bss.kite.manager.inst.KiteProdInst;
import com.iwhalecloud.bss.kite.manager.inst.KiteProdInstFunc;
import com.iwhalecloud.bss.kite.manager.inst.KiteSceneInst;
import com.iwhalecloud.bss.kite.manager.inst.change.KiteInstChange;
import com.iwhalecloud.bss.kite.manager.inst.graph.impl.RelEdge;
import com.iwhalecloud.bss.kite.service.ord.pos.vo.KitePosOfferInstVO;
import com.iwhalecloud.bss.kite.service.ord.pos.vo.KitePosOfferObjInstRelVO;
import com.iwhalecloud.bss.kite.service.ord.pos.vo.KitePosProdInstVO;
import com.ztesoft.bss.base.staticdata.CoreDataOffer;
import com.ztesoft.bss.common.util.SpringUtil;
import com.ztesoft.bss.common.util.StringUtil;
import com.ztesoft.bss.svcability.util.ListUtil;

import edu.emory.mathcs.backport.java.util.Collections;

@Service
public class KitePosGoodsHandler implements IKitePosSceneHandler {

    @Autowired
    private IQuerySceneInstService querySceneInstService;

    @Resource
    private IOperateSceneInstService operateSceneInstService;

    @Autowired
    private IGoodsService goodsService;

    private String skipFlowService;

    private boolean changeInstIdFlag = false;

    private Map<String, String> instIdMap = new HashMap<>();

    @Override
    public void handle(KitePosHandlerContext context) {
        String taskCode = querySceneInstService.getExtParameterValue(context.getSceneInstId(), "taskCode");
        if(KiteStringUtils.isNotEmpty(taskCode) && KiteStringUtils.isEqual("OrderStartRent", taskCode)){
            KitePosGoodsDTO goodsYJJD = context.getPosDto().getGoods().get(0);
            // 起租时，非融合需要走goods节点，融合不走goods节点 .如果是云聚节点则继续往下走(40006660为云聚节点的GoodsCode)
            if (!"40006660".equals(goodsYJJD.getSaleGoodsCode())) {
                Map<String, KitePosOfferInstVO> giftOfferInstMap = context.getPosSceneBO().getGiftOfferInstMap();
                if (KiteMapUtils.isNotEmpty(giftOfferInstMap)) {
                    return;
                }
            }
        }
        this.prepareDeal(context);
        KiteSceneInst kiteSceneInst = querySceneInstService.getSceneInst(context.getSceneInstId());
        String serviceOfferId = kiteSceneInst.getServiceOfferId();

        this.packageGiftOfferInstInfo(context);
        this.packageMainOfferInstInfo(context);
        if (KiteStringUtils.equalsAny(serviceOfferId, LocalServiceOfferConsts.SERVICE_OFFER_COP_MEMBER_JOIN,
            LocalServiceOfferConsts.SERVICE_OFFER_COP_MEMBER_QUIT)) {
            // cop成员加入、退出只需封装成员商品节点，cop的goods节点不需要
            this.packageMemOfferInstInfo(context);
        }

        List<KitePosGoodsDTO> goodsDTOS = context.getPosDto().getGoods();
        //延期时，过滤掉不含有延期模块的goods信息
        if (KiteStringUtils.isEqual(LocalServiceOfferConsts.SERVICE_OFFER_DELAY, serviceOfferId)) {
            dealDelay(context, goodsDTOS);
        }
        if (KiteStringUtils.equalsAny(serviceOfferId, LocalServiceOfferConsts.SERVICE_OFFER_COLLECTION_GROUP_ADD,
            LocalServiceOfferConsts.SERVICE_OFFER_COLLECTION_GROUP_DEL)) {
            List<KitePosGoodsDTO> goodsDTOS1 = context.getPosDto().getGoods();
            List<KitePosUserDTO> kitePosUserDTOS = context.getPosDto().getUsers();
            List<KitePosGoodsDTO> goods = new ArrayList<>();
            KitePosGoodsDTO goodsDTO = goodsDTOS1.get(0);
            for (KitePosUserDTO kitePosUserDTO : kitePosUserDTOS) {
                KitePosGoodsDTO dto = KiteObjectUtils.clone(goodsDTO);
                dto.setUserInstId(kitePosUserDTO.getInstanceId());
                dto.setChangeType(ChangeTypeUtils.CHANGE_TYPE_K);
                dto.getProducts().forEach(prod -> prod.setChangeType(ChangeTypeUtils.CHANGE_TYPE_K));
                goods.add(dto);
            }
            if (KiteListUtils.isNotEmpty(goods)) {
                context.getPosDto().getGoods().clear();
                context.getPosDto().getGoods().addAll(goods);
            }
        }

        if(KiteListUtils.isNotEmpty(goodsDTOS)) {
            // app甩单补录，将goods节点下的code、name、saleGoodsCode复制一份到order节点下（goodsCode、goodsNames、saleGoods）
            String renderOrderType = querySceneInstService.getExtParameterValue(context.getSceneInstId(), "renderOrderType");
            if(KiteStringUtils.isEqual(renderOrderType, "orderRejection")) {
                KitePosGoodsDTO kitePosGoodsDTO = goodsDTOS.get(0);
                KitePosOrderDTO order = context.getPosDto().getOrder();
                order.setGoodsCode(kitePosGoodsDTO.getCode());
                order.setGoodsNames(kitePosGoodsDTO.getName());
                order.setSaleGoods(kitePosGoodsDTO.getSaleGoodsCode());
            }
        }
    }

    /**
     * 延期时，过滤掉不含有延期模块的goods信息
     * 一大坨逻辑影响了主流程的可读性，帮你抽出来
     *
     * @param context
     * @param goodsDTOS
     */
    private void dealDelay(KitePosHandlerContext context, List<KitePosGoodsDTO> goodsDTOS) {
        List<KitePosGoodsDTO> goodsDTOList = new ArrayList<>();
        String postponeRelOffers = querySceneInstService.getCommonAttrValue(context.getSceneInstId(), "relOffers");
        if (!KiteStringUtils.isEmpty(postponeRelOffers)) {
            for (KitePosGoodsDTO dto : goodsDTOS) {
                boolean hasRel = false;
                List<KitePosProductDTO> kitePosProductDTOS = dto.getProducts();
                for (KitePosProductDTO kitePosProductDTO : kitePosProductDTOS) {
                    String instId = kitePosProductDTO.getInstanceId();
                    for (String key : instIdMap.keySet()) {
                        String value = instIdMap.get(key);
                        if (KiteStringUtils.indexOf(postponeRelOffers, key) > -1 && KiteStringUtils.equals(value, instId)) {
                            hasRel = true;
                        }
                    }
                }
                if (hasRel) {
                    goodsDTOList.add(dto);
                }
            }
        }
        if (KiteListUtils.isNotEmpty(goodsDTOList)) {
            context.getPosDto().getGoods().clear();
            context.getPosDto().getGoods().addAll(goodsDTOList);
        }
        List<KitePosUserDTO> kitePosUserDTOS = context.getPosDto().getUsers();
        List<KitePosUserDTO> usersDTOList = new ArrayList<>();
        if (!KiteStringUtils.isEmpty(postponeRelOffers)) {
            for (KitePosUserDTO kitePosUserDTO : kitePosUserDTOS) {
                boolean hasRel = false;
                String relInstId = kitePosUserDTO.getInstanceId();
                for (KitePosGoodsDTO dto : goodsDTOS) {
                    String instId = dto.getUserInstId();
                    if (KiteStringUtils.equals(relInstId, instId)) {
                        hasRel = true;
                        break;
                    }
                }
                if (hasRel) {
                    usersDTOList.add(kitePosUserDTO);
                }
            }
        }
        if (KiteListUtils.isNotEmpty(usersDTOList)) {
            context.getPosDto().getUsers().clear();
            context.getPosDto().getUsers().addAll(usersDTOList);
        }
    }

    private void prepareDeal(KitePosHandlerContext context) {
        this.skipFlowService = DcSystemParamCache.getDcParamVal("skip_flow_service");

        //如果已存在一个以上的订单详情记录，在此进行映射处理，key是极简的实例id，value是订单中心的实例id
        if (context.getPosDto().getGoods().size() > 0) {
            assembleMap(context.getPosDto().getGoods(), instIdMap, context.getCustDto().getCustId(),
                context.getSceneInstId());
            //将订单详情原有部分进行清楚再进行正常拼接，实例id已经再instIdMap映射完毕
            context.getPosDto().getGoods().clear();
            changeInstIdFlag = true;
        }
    }

    private void packageGiftOfferInstInfo(KitePosHandlerContext context) {
        Map<String, KitePosOfferInstVO> giftOfferInstMap = context.getPosSceneBO().getGiftOfferInstMap();
        Iterator<KitePosOfferInstVO> iterator = giftOfferInstMap.values().iterator();
        while (iterator.hasNext()) {
            KitePosOfferInstVO offerInstVO = iterator.next();
            //礼包实例
            KiteOfferInst offerInst = offerInstVO.getOfferInst();

            KitePosGoodsDTO goods = new KitePosGoodsDTO();
            goods.setInstanceId(offerInst.getOfferInstId());
            // 设备类
            if (CuccPosServiceUtils.isRouteUser(context.getSceneInstId(), context.getCustId())) {
                goods.setDestItemId(offerInst.getExtOfferInstId());
            }
            this.packageProductInfoForGiftGoods(context, goods, offerInst.getOfferInstId(), offerInst.getExtOfferInstId());
            this.packageGoodsInfo(context, goods, offerInst);
            this.packagePayRelation(context, goods);
            //资费信息通过可选包获取,只能通过主套餐往下找可选包
            this.packageGoodsFeeInfo(context, goods, offerInst);
            //云联网融合产品ChangeType追单时主产品节点标识为0新增
            this.packageGoodsChangeTypeInfo(context,goods);

            context.addGoods(goods);
        }
    }

    private void packageGoodsChangeTypeInfo(KitePosHandlerContext context, KitePosGoodsDTO goods) {
        String bizType = context.getPosDto().getOrder().getBizType();
        KiteSceneInst sceneInst = querySceneInstService.getSceneInst(context.getSceneInstId());
        String serviceOfferId = sceneInst.getServiceOfferId();
        if (KiteStringUtils.isEqual(serviceOfferId, LocalServiceOfferConsts.SERVICE_OFFER_FOLLOW)&&
            KiteStringUtils.isEqual(bizType, "1001")){
            goods.setChangeType(ChangeTypeUtils.CHANGE_TYPE_A);
            List<KitePosProductDTO> products = goods.getProducts();
            if (CollectionUtils.isNotEmpty(products)){
                for (KitePosProductDTO product : products) {
                    product.setChangeType(ChangeTypeUtils.CHANGE_TYPE_A);
                }
            }
        }
    }

    private void packageMemOfferInstInfo(KitePosHandlerContext context) {
        Map<String, KitePosOfferInstVO> memOfferInstMap = context.getPosSceneBO().getMemOfferInstMap();
        Iterator<KitePosOfferInstVO> iterator = memOfferInstMap.values().iterator();
        List<KitePosOfferInstVO> addRoleOfferInsts = Lists.newArrayList();

        KiteSceneInst kiteSceneInst = this.querySceneInstService.getSceneInst(context.getSceneInstId());

        while (iterator.hasNext()) {
            KitePosOfferInstVO offerInstVO = iterator.next();
            //套餐实例
            KiteOfferInst offerInst = offerInstVO.getOfferInst(); //套餐实例
            if (this.isAddRoleOfferInst(offerInst)) {
                addRoleOfferInsts.add(offerInstVO);
                continue;
            }
            // 20210429 收入归集集团成员加入退出添加，来回切换加入/退出成员号码，对D的不做处理
            if (KiteStringUtils.equalsAny(kiteSceneInst.getServiceOfferId(),
                LocalServiceOfferConsts.SERVICE_OFFER_COLLECTION_GROUP_ADD,
                LocalServiceOfferConsts.SERVICE_OFFER_COLLECTION_GROUP_DEL) && Objects
                .equals(ActionType.D, offerInst.getActionType())) {
                continue;
            }
            List<KitePosOfferObjInstRelVO> objInstRels = offerInstVO.getOfferObjInstRels(); //套餐销售品包含产品
            KitePosGoodsDTO goods = new KitePosGoodsDTO();

            goods.setInstanceId(offerInst.getOfferInstId());
            goods.setCode(offerInst.getOfferId());
            // 设备类
            if (CuccPosServiceUtils.isRouteUser(context.getSceneInstId(), context.getCustId())) {
                goods.setDestItemId(offerInst.getExtOfferInstId());
            }
            KiteOfferInst parentOfferInst  = this.querySceneInstService.getParentOfferInstByOfferInstId(context.getCustId(), offerInst.getOfferInstId());
            if (!KiteObjectUtils.isEmpty(parentOfferInst)) {
                goods.setParentInstId(Optional.ofNullable(parentOfferInst).map(KiteOfferInst::getOfferInstId).orElse(""));
            }
            else {
                KitePosGoodsDTO parGoodsDto = context.getPosDto().getGoods().get(0);
                goods.setParentInstId(Optional.ofNullable(parGoodsDto).map(KitePosGoodsDTO::getInstanceId).orElse(""));
            }
            this.packageProductInfo(context, goods, objInstRels, offerInst.getExtOfferInstId());
            this.packageGoodsInfo(context, goods, offerInst);
            this.packagePayRelation(context, goods);

            //资费信息通过可选包获取,只能通过主套餐往下找可选包
            this.packageGoodsFeeInfo(context, goods, offerInst);
            String userInfoJson = offerInst.getAttrValue("userInfo");
            if (KiteStringUtils.isEmpty(userInfoJson)) {
                continue;
            }
            List<Map> memUsers = JSONObject.parseArray(userInfoJson, Map.class);
            Map userDto = memUsers.get(0);
            goods.setUserInstId(CommonUtil.getInstanceId(LocalKeyConsts.YH_INST_CODE, KiteMapUtils.getString(userDto, "instance_id")));

            context.addGoods(goods);
        }
    }

    private void packageMainOfferInstInfo(KitePosHandlerContext context) {
        Map<String, KitePosOfferInstVO> mainOfferInstMap = context.getPosSceneBO().getMainOfferInstMap();
//        System.out.println("封装主套餐：" + JSON.toJSONString(mainOfferInstMap));
        Iterator<KitePosOfferInstVO> iterator = mainOfferInstMap.values().iterator();

        Map<String, KitePosOfferInstVO> giftOfferInstMap = context.getPosSceneBO().getGiftOfferInstMap();
        List<KitePosOfferInstVO> addRoleOfferInsts = Lists.newArrayList();

        KiteSceneInst kiteSceneInst = this.querySceneInstService.getSceneInst(context.getSceneInstId());

        while (iterator.hasNext()) {
            KitePosOfferInstVO offerInstVO = iterator.next();
            //套餐实例
            KiteOfferInst offerInst = offerInstVO.getOfferInst(); //套餐实例
            if (this.isAddRoleOfferInst(offerInst)) {
                addRoleOfferInsts.add(offerInstVO);
                continue;
            }
            // 20210429 收入归集集团成员加入退出添加，来回切换加入/退出成员号码，对D的不做处理
            if (KiteStringUtils.equalsAny(kiteSceneInst.getServiceOfferId(),
                LocalServiceOfferConsts.SERVICE_OFFER_COLLECTION_GROUP_ADD,
                LocalServiceOfferConsts.SERVICE_OFFER_COLLECTION_GROUP_DEL) && Objects.equals(ActionType.D, offerInst.getActionType())) {
                continue;
            }
            if (Objects.equals(offerInst.getInstType(), InstType.MEM_OFFER_INST)) {
                continue;
            }
            List<KitePosOfferObjInstRelVO> objInstRels = offerInstVO.getOfferObjInstRels(); //套餐销售品包含产品
            KitePosGoodsDTO goods = new KitePosGoodsDTO();
            goods.setInstanceId(offerInst.getOfferInstId());
            goods.setCode(offerInst.getOfferId());
            // 设备类
            if (CuccPosServiceUtils.isRouteUser(context.getSceneInstId(), context.getCustId())) {
                goods.setDestItemId(offerInst.getExtOfferInstId());
            }
            this.packageProductInfo(context, goods, objInstRels, offerInst.getExtOfferInstId());
            this.packageGoodsInfo(context, goods, offerInst);
            //如果存在融合销售品,成员商品取融合壳子的payRelation节点,否则按原逻辑处理
            if (KiteMapUtils.isEmpty(giftOfferInstMap)) {
                this.packagePayRelation(context, goods);
            } else {
                Iterator<KitePosOfferInstVO> giftIterator = giftOfferInstMap.values().iterator();
                KitePosOfferInstVO giftOfferInstVO = giftIterator.next();
                KiteOfferInst giftOfferInst = giftOfferInstVO.getOfferInst();
                KitePosGoodsDTO kitePosGiftGoodsDTO = context.getPosDto().getGoods().stream()
                    .filter(good -> giftOfferInst.getOfferInstId().equals(good.getInstanceId())).findAny()
                    .orElse(new KitePosGoodsDTO());
                if (!KiteObjectUtils.isEmpty(kitePosGiftGoodsDTO) && KiteListUtils
                    .isNotEmpty(kitePosGiftGoodsDTO.getPayRelation())) {
                    List<KitePosGoodsPayRealtionDTO> payRelation = kitePosGiftGoodsDTO.getPayRelation();
                    List<KitePosGoodsPayRealtionDTO> payRelationClon = KiteBeanUtils
                        .copyPropsForList(payRelation, KitePosGoodsPayRealtionDTO.class);
                    goods.setPayRelation(toTrans(payRelationClon));
                }
            }
            //资费信息通过可选包获取,只能通过主套餐往下找可选包
            this.packageGoodsFeeInfo(context, goods, offerInst);
            context.addGoods(goods);
        }
        //附加产品-补充通信包使用产品支持，但是补充通信包在产商品侧配置的是属性组且可以订购多次，这里需要判断多个产品实例就用属性组形式传到下游系统
        addRoleOfferInsts.forEach(offerInstVO -> {
            //套餐实例
            KiteOfferInst offerInst = offerInstVO.getOfferInst(); //套餐实例
            List<KitePosOfferObjInstRelVO> objInstRels = offerInstVO.getOfferObjInstRels(); //套餐销售品包含产品
            if (KiteListUtils.isEmpty(objInstRels)) {
                List<KiteInstDTO> kiteOfferInstDetails = querySceneInstService
                    .listOfferInstDetails(context.getCustId(), offerInst.getOfferInstId());
                for (KiteInstDTO offerInstDetails : kiteOfferInstDetails) {
                    Set<RelEdge> subEdges = offerInstDetails.getSubEdges();
                    for (RelEdge subEdge : subEdges) {
                        KitePosOfferObjInstRelVO objInstRelVO = new KitePosOfferObjInstRelVO();
                        objInstRelVO.setInstId(subEdge.getTargetInstId());
                        objInstRelVO.setObjType(subEdge.getTargetInstType().name());
                        objInstRels.add(objInstRelVO);
                    }
                }
            }

            //获取相同的附加产品
            KitePosGoodsDTO goods = null;
            List<KitePosGoodsDTO> goodsList = context.getPosDto().getGoods().stream()
                .filter(gg -> KiteStringUtils.equals(gg.getCode(), offerInst.getOfferId())).collect(Collectors.toList());
            if (!KiteListUtils.isEmpty(goodsList)) {
                goods = goodsList.get(0);
                context.getPosDto().getGoods().removeIf(gg -> KiteStringUtils.equals(gg.getCode(), offerInst.getOfferId()));
            }
            if (KiteObjectUtils.isEmpty(goods)) {
                goods = new KitePosGoodsDTO();
            }
            // 设备类
            if (CuccPosServiceUtils.isRouteUser(context.getSceneInstId(), context.getCustId())) {
                goods.setDestItemId(offerInst.getExtOfferInstId());
            }
            goods.setInstanceId(offerInst.getOfferInstId());
            this.packageAddRoleProductInfo(context, goods, objInstRels, offerInst.getExtOfferInstId());
            String oldChangeType = goods.getChangeType();
            this.packageGoodsInfo(context, goods, offerInst);
            String newChangeType = ChangeTypeUtils.getChangeType(offerInst.getActionType().name());
            // 特殊处理补充产品的changetype
            if (StringUtils.isNotEmpty(oldChangeType) && !StringUtils.equals(oldChangeType, newChangeType)) {
                goods.setChangeType(ChangeTypeUtils.CHANGE_TYPE_K);
            }
            //资费信息通过可选包获取,只能通过主套餐往下找可选包
            this.packageGoodsFeeInfo(context, goods, offerInst);
            context.addGoods(goods);
        });

        // 订单中心配套改造,归集后的转单报文中实例ID不替换为订单中心的ID
        String flag = querySceneInstService.getExtParameterValue(context.getSceneInstId(), LocalKeyConsts.ADD_ORDE);
        //正常拼接报文后，再进行实例id的替换
        if (changeInstIdFlag && MapUtils.isNotEmpty(instIdMap) && !KiteStringUtils.isEqual("T", flag)) {
            context.getPosDto().getGoods().forEach(kitePosGoodsDTO -> {
                Offer offer = OfferCache.get(kitePosGoodsDTO.getCode());
                //userInstId
                if (!KiteObjectUtils.isEmpty(context.getPosDto().getUsers())) {
                    List<KiteProdInst> prodInsts = querySceneInstService
                        .listProdInstsFromOfferInst(context.getCustId(), kitePosGoodsDTO.getInstanceId());
                    // 过滤掉资费计划产品
                    prodInsts = prodInsts.stream().filter(prodInst -> !KiteStringUtils.equals(LocalKeyConsts.PROD_USE_TYPE_2000, ProductCache.get(prodInst.getSpecId()).getProdUseType())).collect(Collectors.toList());
                    if (!KiteListUtils.isEmpty(prodInsts)) {
                        // 业务变更初始化礼包和主套餐的时候，记录了对应产品实例和业务号码的关系
                        Map<String, String> instSerialNumberMap = querySceneInstService
                            .getExtParameterValue(context.getSceneInstId(), "instSerialNumberMap");
                        prodInsts.forEach(prodInst -> {
                            if (KiteMapUtils.isNotEmpty(instSerialNumberMap)) {
                                // 变更
                                String serialNumber = KiteMapUtils
                                    .getString(instSerialNumberMap, prodInst.getProdInstId());
                                String instanceId = context.getPosDto().getUsers().stream()
                                    .filter(user -> KiteStringUtils.isEqual(serialNumber, user.getSerialNumber()))
                                    .findAny().map(KitePosUserDTO::getInstanceId).orElse("");
                                kitePosGoodsDTO.setUserInstId(instanceId);
                            } else {
                                // 非变更
                                KiteAttr busiNbrAttr = prodInst.getAttr("200002981");
                                if (CuccPosServiceUtils.isBatchAccept(context.getSceneInstId())
                                    || BatchAcceptUtil.isBatchSign(context.getSceneInstId())) {
                                    busiNbrAttr = prodInst.getAttr("serial_number");
                                }
                                if (!KiteObjectUtils.isEmpty(busiNbrAttr)) {
                                    KiteAttr finalBusiNbrAttr = busiNbrAttr;
                                    String instanceId = context.getPosDto().getUsers().stream().filter(
                                        user -> KiteStringUtils.isEqual(finalBusiNbrAttr.getValue(), user.getSerialNumber()))
                                        .findAny().map(KitePosUserDTO::getInstanceId).orElse("");
                                    kitePosGoodsDTO.setUserInstId(instanceId);
                                }
                            }
                        });
                        if (GoodsInfoTransfer.isAddRoleOffer(kitePosGoodsDTO.getCode(), offer.getCateId())) {
                            // 附加商品，用户实例设置为主商品的用户实例
                            List<KiteInstRelDTO> offerInstRels = querySceneInstService
                                .listInstRelsByZInst(context.getCustId(), InstType.MAIN_OFFER_INST,
                                    kitePosGoodsDTO.getInstanceId(), InstType.MAIN_OFFER_INST);
                            offerInstRels = offerInstRels.stream().filter(
                                rel -> java.util.Objects.equals(RelType.OFFER_OBJ_REL_TYPE_120000, rel.getRelType()))
                                .collect(Collectors.toList());
                            for (KiteInstRelDTO aOfferInst : offerInstRels) {
                                KiteOfferInst mainOfferInst = querySceneInstService
                                    .getOfferInst(context.getCustId(), aOfferInst.getaInstId());
                                if (!KiteObjectUtils.isEmpty(mainOfferInst)) {
                                    prodInsts = querySceneInstService.listProdInstsFromOfferInst(context.getCustId(),
                                        mainOfferInst.getOfferInstId());
                                    prodInsts = prodInsts.stream().filter(prodInst -> !KiteStringUtils.equals(LocalKeyConsts.PROD_USE_TYPE_2000, ProductCache.get(prodInst.getSpecId()).getProdUseType())).collect(Collectors.toList());
                                    prodInsts.forEach(prodInst -> {
                                        KiteAttr busiNbrAttr = prodInst.getAttr("200002981");
                                        if (!KiteObjectUtils.isEmpty(busiNbrAttr)) {
                                            String instanceId = context.getPosDto().getUsers().stream().filter(
                                                user -> KiteStringUtils
                                                    .isEqual(busiNbrAttr.getValue(), user.getSerialNumber())).findAny()
                                                .map(KitePosUserDTO::getInstanceId).orElse("");
                                            kitePosGoodsDTO.setUserInstId(instanceId);
                                        }
                                    });
                                }
                            }
                            if (!Objects.equals(InstType.GIFT_OFFER_INST, kiteSceneInst.getRootInstType()) && KiteStringUtils.isEmpty(kitePosGoodsDTO.getUserInstId())) {
                                //匹配主业务号码
                                String business_number = querySceneInstService
                                    .getExtParameterValue(context.getSceneInstId(), "business_number");
                                String instanceId = context.getPosDto().getUsers().stream()
                                    .filter(user -> business_number.equals(user.getSerialNumber())).findAny()
                                    .map(KitePosUserDTO::getInstanceId).orElse("");
                                kitePosGoodsDTO.setUserInstId(instanceId);
                            }
                        }
                    }
                    // 附加商品最后统一处理userInstId
                    if (GoodsInfoTransfer.isAddRoleOffer(kitePosGoodsDTO.getCode(), offer.getCateId())) {
                        dealAddRoleUserInstId(kitePosGoodsDTO, context);
                    }
                    dealUserInstId(context, kitePosGoodsDTO, context.getPosDto().getUsers());
                    //匹配主业务号码
//                    if (KiteStringUtils.isEmpty(kitePosGoodsDTO.getUserInstId())) {
//                        String business_number = querySceneInstService
//                            .getExtParameterValue(context.getSceneInstId(), "business_number");
//                        String instanceId = context.getPosDto().getUsers().stream()
//                            .filter(user -> business_number.equals(user.getSerialNumber())).findAny()
//                            .map(KitePosUserDTO::getInstanceId).orElse("");
//                        kitePosGoodsDTO.setUserInstId(instanceId);
//                    }
                }
                //pay的实例替换
//                List<KitePosGoodsPayRealtionDTO> KitePosGoodsPayRealtionDtoList = kitePosGoodsDTO.getPayRelation();
//                if (KiteListUtils.isNotEmpty(KitePosGoodsPayRealtionDtoList)) {
//                    for (KitePosGoodsPayRealtionDTO KitePosGoodsPayRealtionDto : KitePosGoodsPayRealtionDtoList) {
//                        if (KiteStringUtils.isNotEmpty(instIdMap.get("pay" + KitePosGoodsPayRealtionDto.getAccountInstId()))) {
//                            KitePosGoodsPayRealtionDto.setInstanceId(instIdMap.get("pay" + KitePosGoodsPayRealtionDto.getAccountInstId()));
//                        }
//                    }
//                }
//                //产品的实例替换
//                List<KitePosProductDTO> kitePosProductDTOList = kitePosGoodsDTO.getProducts();
//                for (KitePosProductDTO kitePosProductDTO : kitePosProductDTOList) {
//                    if (KiteStringUtils.isNotEmpty(instIdMap.get(kitePosProductDTO.getInstanceId()))) {
//                        kitePosProductDTO.setInstanceId(instIdMap.get(kitePosProductDTO.getInstanceId()));
//                    }
//                }
            });
        }

    }

    private boolean isAddRoleOfferInst(KiteOfferInst offerInst) {
        String categoryId = Optional.ofNullable(OfferCache.get(offerInst.getOfferId())).map(Offer::getCateId).orElse("");
        return GoodsInfoTransfer.isAddRoleOffer(offerInst.getOfferId(), categoryId);
    }

    private List<KitePosGoodsPayRealtionDTO> toTrans(List<KitePosGoodsPayRealtionDTO> payRelation) {
        if (!ListUtil.isEmpty(payRelation)) {
            payRelation.stream().forEach(dto -> {
                dto.setInstanceId(IdUtils.generateInstId(InstType.PROD_INST_ACCT));
            });
        }
        return payRelation;
    }

    //组装映射map
    private void assembleMap(List<KitePosGoodsDTO> goodsList, Map<String, String> instIdMap, String custId, String sceneInstId) {
        List<KiteOfferInst> offerInstList = querySceneInstService.listMainOfferInsts(sceneInstId);
        List<KiteProdInst> kiteProdInstList = querySceneInstService.listProdInsts(sceneInstId);
        for (KitePosGoodsDTO posGoodsDTO : goodsList) {
            //商品
            String kiteOfferInstId = offerInstList.stream()
                .filter(kiteOfferInst -> kiteOfferInst.getSpecId().equals(posGoodsDTO.getCode())).findAny().
                    map(KiteOfferInst::getOfferInstId).orElse("");
            if (StringUtil.isNotEmpty(kiteOfferInstId)) {
                instIdMap.put(kiteOfferInstId, posGoodsDTO.getInstanceId());

                if (KiteListUtils.isNotEmpty(posGoodsDTO.getPayRelation())) {
                    for (KitePosGoodsPayRealtionDTO kitePosGoodsPayRealtionDTO : posGoodsDTO.getPayRelation()) {
                        //通过pay+规格code定位 PayRealtion的实例id
                        instIdMap.put("pay" + kitePosGoodsPayRealtionDTO.getAccountInstId(), kitePosGoodsPayRealtionDTO.getInstanceId());
                    }
                }
            }
            //产品
            posGoodsDTO.getProducts().forEach(posProductDTO -> {
                for (KiteProdInst kiteProdInst : kiteProdInstList) {
                    if (kiteProdInst.getSpecId().equals(posProductDTO.getCode())) {
                        instIdMap.put(kiteProdInst.getProdInstId(), posProductDTO.getInstanceId());
                    }
                }
            });

        }
    }

    private void packageGoodsInfo(KitePosHandlerContext context, KitePosGoodsDTO goods, KiteOfferInst offerInst) {
        goods.setInstanceId(offerInst.getInstId());
        goods.setCode(offerInst.getOfferId());
        goods.setCount(1);
        goods.setName(offerInst.getOfferName());
        Offer curOffer = OfferCache.get(offerInst.getOfferId());
        // 设置商品分类编码
        if (Objects.nonNull(curOffer) && GeneralSwitchUtils.isSwitchOpened("SET_CATAGORY_ID")) {
            goods.setCatagoryId(curOffer.getCateId());
        }
        String change = ChangeTypeUtils.getChangeType(offerInst.getActionType().name());
        if (KiteStringUtils.isEqual(change, ChangeTypeUtils.CHANGE_TYPE_M)) {
            change = ChangeTypeUtils.CHANGE_TYPE_K;
        }
        goods.setChangeType(change);

        IQuerySceneInstService querySceneInstService = SpringUtil.getBean(IQuerySceneInstService.class);
        KiteSceneInst sceneInst = querySceneInstService.getSceneInst(context.getSceneInstId());
        InstType instType = sceneInst.getRootInstType();

        // 融合的付费关系、合同、折扣审批都挂在融合壳子上
        String offerInstId = offerInst.getOfferInstId();
        if (Objects.equals(InstType.GIFT_OFFER_INST, instType)) {
            offerInstId = sceneInst.getRootInstId();
        }
        //用户实例
        List<KitePosUserDTO> users = context.getPosDto().getUsers();
        if (!KiteListUtils.isEmpty(users)) {
            //先匹配产品的业务号码
            List<KiteProdInst> prodInsts = querySceneInstService
                .listProdInstsFromOfferInst(context.getCustId(), offerInst.getOfferInstId());
            if (!KiteListUtils.isEmpty(prodInsts)) {
                prodInsts.forEach(prodInst -> {
                    // 获取业务号码产品属性
                    KiteAttr busiNbrAttr;
                    if (CuccPosServiceUtils.isBatchAccept(sceneInst.getSceneInstId())
                        || BatchAcceptUtil.isBatchSign(sceneInst.getSceneInstId())) {
                        busiNbrAttr = prodInst.getAttr("serial_number");
                    } else {
                        busiNbrAttr = prodInst.getAttr("200002981");
                    }
                    if (!KiteObjectUtils.isEmpty(busiNbrAttr)) {
                        String instanceId = users.stream()
                            .filter(user -> KiteStringUtils.isEqual(busiNbrAttr.getValue(), user.getSerialNumber()))
                            .findAny().map(KitePosUserDTO::getInstanceId).orElse("");
                        goods.setUserInstId(instanceId);
                    }
                });
                if (GoodsInfoTransfer.isAddRoleOffer(offerInst.getSpecId(), curOffer.getCateId())) {
                    // 附加商品，用户实例设置为主商品的用户实例
//                    List<KiteInstRelDTO> offerInstRels = querySceneInstService
//                        .listInstRelsByZInst(context.getCustId(), InstType.MAIN_OFFER_INST, offerInst.getOfferInstId(),
//                            InstType.MAIN_OFFER_INST);
                    List<KiteInstRelDTO> offerInstRels = querySceneInstService.listInstRelsByZInst(context.getCustDto().getCustId(), InstType.MAIN_OFFER_INST, offerInst.getOfferInstId(),
                        InstType.MAIN_OFFER_INST, Arrays.asList(ActionType.values()));
                    offerInstRels = offerInstRels.stream()
                        .filter(rel -> java.util.Objects.equals(RelType.OFFER_OBJ_REL_TYPE_120000, rel.getRelType())).collect(Collectors.toList());
                    for (KiteInstRelDTO aOfferInst : offerInstRels) {
                        KiteOfferInst mainOfferInst = querySceneInstService.getOfferInst(context.getCustId(), aOfferInst.getaInstId());
                        if (!KiteObjectUtils.isEmpty(mainOfferInst)) {
                            prodInsts = querySceneInstService
                                .listProdInstsFromOfferInst(context.getCustId(), mainOfferInst.getOfferInstId());
                            prodInsts.forEach(prodInst -> {
                                // 获取业务号码产品属性
                                KiteAttr busiNbrAttr = prodInst.getAttr("200002981");
                                if (!KiteObjectUtils.isEmpty(busiNbrAttr)) {
                                    String instanceId = users.stream().filter(
                                        user -> KiteStringUtils.isEqual(busiNbrAttr.getValue(), user.getSerialNumber()))
                                        .findAny().map(KitePosUserDTO::getInstanceId).orElse("");
                                    goods.setUserInstId(instanceId);
                                }
                            });
                        }
                    }
                }
            }
            /* 订单中心配套改造,归集后的转单报文中实例ID不替换为订单中心的ID
            dealUserInstId(context, goods, users);
            */
            //匹配主业务号码
            if (KiteStringUtils.isEmpty(goods.getUserInstId())) {
                String business_number = querySceneInstService
                    .getExtParameterValue(context.getSceneInstId(), "business_number");
                String instanceId = users.stream().filter(user -> KiteStringUtils.equals(business_number, user.getSerialNumber()))
                    .findAny().map(KitePosUserDTO::getInstanceId).orElse("");
                goods.setUserInstId(instanceId);
            }
        }
        //账户
        List<KiteOfferInstAcct> offerInstAcctRels = querySceneInstService
            .listOfferInstAccts(context.getCustId(), offerInstId);
        if (KiteListUtils.isEmpty(offerInstAcctRels)) {
            String custId = querySceneInstService.getSceneInst(context.getSceneInstId()).getCustId();
            offerInstAcctRels = querySceneInstService
                .listOfferInstAccts(custId, offerInstId);
        }
        if (CuccPosServiceUtils.isGoodsModifyScene(context.getSceneInstId())) {
            if (!KiteListUtils.isEmpty(offerInstAcctRels)) {
                // 过滤动作为D的以及非默认账户
                offerInstAcctRels.removeIf(offerInstAcctRel ->
                    KiteStringUtils.isEqual(offerInstAcctRel.getActionType().name(), ActionType.D.name()) || !KiteStringUtils.isEqual(offerInstAcctRel.getIsDefault(), "1"));
                offerInstAcctRels = offerInstAcctRels.stream()
                    .filter((acct) -> goods.getInstanceId().equals(acct.getOfferInstId())).collect(Collectors.toList());
                if (!KiteListUtils.isEmpty(offerInstAcctRels)) {
                    KiteOfferInstAcct acctRel = offerInstAcctRels.get(0);
                    goods.setAccountInstId(getAccountInstId(context, acctRel.getAcctId(), acctRel.getActionType().name()));
                }
            } else {
                //如果是商品变更,且上面直接获取实例下账户为空,那么这个应该是旧套餐对象,找出删除的实例挂上去
                List<KiteInstChange> instChangeList = querySceneInstService.listInstChanges(context.getSceneInstId(), InstType.OFFER_INST_ACCT).stream()
                    .filter(instChange -> goods.getInstanceId().equals(instChange.getInstId()))
                    .filter(instChange -> ActionType.D.name().equals(instChange.getNewValue()))
                    .filter(instChange -> !ActionType.A.name().equals(instChange.getOldValue()))
                    .collect(Collectors.toList());
                List<KiteOfferInstAcct> delOfferInstAccts = querySceneInstService.listInsts(context.getSceneInstId(), Collections.singletonList(InstType.OFFER_INST_ACCT));
                for (KiteInstChange instChange : instChangeList) {
                    delOfferInstAccts.forEach((acctRel) -> {
                        if (KiteStringUtils.isEqual(ActionType.D.name(), acctRel.getActionType().name())
                            && KiteStringUtils.isEqual(instChange.getSubInstId(), acctRel.getInstId())) {
                            goods.setAccountInstId(getAccountInstId(context, acctRel.getAcctId(), acctRel.getActionType().name()));
                        }
                    });
                }
            }
        } else {
            if (!KiteListUtils.isEmpty(offerInstAcctRels) && !KiteStringUtils.equalsAny(sceneInst.getServiceOfferId(), LocalServiceOfferConsts.SERVICE_OFFER_COLLECTION_GROUP_ADD, LocalServiceOfferConsts.SERVICE_OFFER_COLLECTION_GROUP_DEL)) {
                // 过滤动作为D的以及非默认账户
                offerInstAcctRels.removeIf(offerInstAcctRel ->
                    KiteStringUtils.isEqual(offerInstAcctRel.getActionType().name(), ActionType.D.name()) || !KiteStringUtils.isEqual(offerInstAcctRel.getIsDefault(), "1"));
                offerInstAcctRels = offerInstAcctRels.stream()
                    .filter((acct) -> goods.getInstanceId().equals(acct.getOfferInstId())).collect(Collectors.toList());
                if (!KiteListUtils.isEmpty(offerInstAcctRels)) {
                    goods.setAccountInstId(
                        Optional.ofNullable(offerInstAcctRels.get(0)).map((acct) -> acct.getInstId()).orElse(""));
                }
            }
        }
        //合同
        List<KiteOfferInstContract> offerInstContractRels = querySceneInstService
            .listOfferInstContracts(context.getCustId(), offerInstId);
        if (KiteListUtils.isEmpty(offerInstContractRels)) {
            String custId = querySceneInstService.getSceneInst(context.getSceneInstId()).getCustId();
            offerInstContractRels = querySceneInstService
                .listOfferInstContracts(custId, offerInstId);
        }
        if (!KiteListUtils.isEmpty(offerInstContractRels) && !KiteStringUtils.equalsAny(sceneInst.getServiceOfferId(), LocalServiceOfferConsts.SERVICE_OFFER_COLLECTION_GROUP_ADD, LocalServiceOfferConsts.SERVICE_OFFER_COLLECTION_GROUP_DEL)) {
            if (!ServiceOfferConsts.SERVICE_OFFER_ORDER.equals(sceneInst.getServiceOfferId()) && KeyConsts.IFTRUE_T
                .equals(querySceneInstService.getExtParameterValue(context.getSceneInstId(), LocalKeyConsts.BUSI_CHANGE_SCENE))) {
                if (offerInstContractRels.size() == 1) {
                    goods.setContractInstId(
                        CommonUtil.getInstanceId(LocalKeyConsts.HT_INST_CODE, Optional.ofNullable(offerInstContractRels.get(0)).map((offerInstContractRel) -> offerInstContractRel.getInstId()).orElse("")));
                } else {
                    List<String> contractInstId = Lists.newArrayList();
                    for (KiteOfferInstContract offerInstContractRel : offerInstContractRels) {
                        contractInstId.add(CommonUtil.getInstanceId(LocalKeyConsts.HT_INST_CODE, offerInstContractRel.getInstId()));
                    }
                    goods.setContractInstId(JSONObject.toJSONString(contractInstId.toArray()));
                }
            } else {
                if (offerInstContractRels.size() == 1) {
                    goods.setContractInstId(Optional.ofNullable(offerInstContractRels.get(0))
                        .map((offerInstContractRel) -> offerInstContractRel.getInstId()).orElse(""));
                } else {
                    List<String> contractInstId = Lists.newArrayList();
                    for (KiteOfferInstContract offerInstContractRel : offerInstContractRels) {
                        contractInstId.add(offerInstContractRel.getInstId());
                    }
                    goods.setContractInstId(JSONObject.toJSONString(contractInstId.toArray()));
                }
            }

        }
        //设置折扣审批实例
        List<KiteOfferInstDiscount> offerInstDiscounts = querySceneInstService
            .listOfferInstDiscounts(context.getCustId(), offerInstId);
        if (!KiteListUtils.isEmpty(offerInstDiscounts) && !KiteStringUtils.equalsAny(sceneInst.getServiceOfferId(), LocalServiceOfferConsts.SERVICE_OFFER_COLLECTION_GROUP_ADD, LocalServiceOfferConsts.SERVICE_OFFER_COLLECTION_GROUP_DEL)) {
            //转单强制默认挂在主商品上 add by sqy 2020.11.11
            List<KiteInstRelDTO> instRels = querySceneInstService
                .listInstRelsByZInst(context.getCustDto().getCustId(), InstType.MAIN_OFFER_INST,
                    offerInst.getOfferInstId(), InstType.MAIN_OFFER_INST);
            if (!KiteListUtils.isEmpty(instRels)) {

            } else {
                goods.setDiscountInstId(Optional.ofNullable(offerInstDiscounts.get(0))
                    .map((offerInstDiscount) -> offerInstDiscount.getInstId()).orElse(""));
            }
        }
        //收货信息实例
        List<Map<String, Object>> deliveryInfos = querySceneInstService
            .getExtParameterValue(context.getSceneInstId(), "offerInstDeliveryInfos");
        if (!KiteListUtils.isEmpty(deliveryInfos) && !KiteStringUtils.equalsAny(sceneInst.getServiceOfferId(), LocalServiceOfferConsts.SERVICE_OFFER_COLLECTION_GROUP_ADD, LocalServiceOfferConsts.SERVICE_OFFER_COLLECTION_GROUP_DEL)) {
            String instId = offerInst.getOfferInstId();
            for (Map<String, Object> delivery : deliveryInfos) {
                List<KiteAttr> kiteAttrs = (List<KiteAttr>) delivery.get("kiteAttrs");

                for (KiteAttr attr : kiteAttrs) {
                    if (KiteStringUtils.equals("offerName", attr.getFieldName()) && KiteStringUtils
                        .equals(attr.getValue(), instId)) {
                        goods.setDeliveryInstId(delivery.get("instId").toString());
                        break;
                    }
                }
            }
        }

        if (KiteStringUtils.equalsAny(sceneInst.getServiceOfferId(),
            LocalServiceOfferConsts.SERVICE_OFFER_COLLECTION_GROUP_ADD,
            LocalServiceOfferConsts.SERVICE_OFFER_COLLECTION_GROUP_DEL) && !KiteStringUtils.equals(goods.getInstanceId(), sceneInst.getRootInstId())) {
            goods.setParentInstId(sceneInst.getRootInstId());
        } else if (Objects.equals(InstType.GIFT_OFFER_INST, instType) && KiteStringUtils
            .equals(KeyConsts.OFFER_TYPE_11, OfferCache.get(offerInst.getOfferId()).getOfferType())
            && !GoodsInfoTransfer.isAddRoleOffer(offerInst.getSpecId(), offerInst.getAttr("cateId").getDefaultValue())) {
            goods.setParentInstId(sceneInst.getRootInstId());
        } else {
            //转单时成员商品实例的parentInstId取主商品实例的实例ID
            if (!KiteObjectUtils.isEmpty(offerInst.getAttr("cateId"))
                && GoodsInfoTransfer.isAddRoleOffer(offerInst.getSpecId(), offerInst.getAttr("cateId").getDefaultValue())) {
                if (Objects.equals(InstType.MAIN_OFFER_INST, instType)) {
                    List<KiteOfferInst> mainOfferInsts = querySceneInstService.listMainOfferInsts(context.getSceneInstId());
                    mainOfferInsts = mainOfferInsts.stream().filter(offerInst1 -> !GoodsInfoTransfer
                        .isAddRoleOffer(offerInst1.getSpecId(), offerInst1.getAttr("cateId").getDefaultValue())).collect(Collectors.toList());
                    if (!KiteListUtils.isEmpty(mainOfferInsts) && GoodsInfoTransfer
                        .isAddRoleOffer(offerInst.getSpecId(), offerInst.getAttr("cateId").getDefaultValue())) {
                        goods.setParentInstId(mainOfferInsts.get(0).getOfferInstId());
                    }
                } else {
                    /*List<KiteInstRelDTO> instRels = querySceneInstService.listInstRelsByZInst(context.getCustDto().getCustId(), InstType.MAIN_OFFER_INST, offerInst.getOfferInstId(), InstType.MAIN_OFFER_INST);
                    if (!KiteListUtils.isEmpty(instRels)) {
                        goods.setParentInstId(instRels.get(0).getaInstId());
                    }*/
                    List<KiteInstRelDTO> instRels = querySceneInstService.listInstRelsByZInst(context.getCustDto().getCustId(), InstType.MAIN_OFFER_INST, offerInst.getOfferInstId(),
                        InstType.MAIN_OFFER_INST, Arrays.asList(ActionType.values()));
                    instRels = instRels.stream().filter(rel -> Objects.equals(RelType.OFFER_OBJ_REL_TYPE_120000, rel.getRelType()))
                        .collect(Collectors.toList());
                    if (!KiteListUtils.isEmpty(instRels)) {
                        goods.setParentInstId(instRels.get(0).getaInstId());
                    }
                }
            }
        }

        if (!ServiceOfferConsts.SERVICE_OFFER_ORDER.equals(sceneInst.getServiceOfferId()) && !LocalServiceOfferConsts.SERVICE_OFFER_ORDER_OPPER.equals(sceneInst.getServiceOfferId()) && KeyConsts.IFTRUE_T.equals(
            querySceneInstService.getExtParameterValue(context.getSceneInstId(), LocalKeyConsts.BUSI_CHANGE_SCENE))) {
            if (KiteStringUtils.isNotEmpty(goods.getAccountInstId())) {
                goods.setAccountInstId(CommonUtil.getInstanceId(LocalKeyConsts.ZH_INST_CODE, goods.getAccountInstId()));
            }

        }
        //关联payment节点,目前总部应用payment节点长度只会是0或1,按照订单中心提供口径,payment和goods节点为一对一关系
        List<KitePosPaymentDTO> payments = context.getPosDto().getPayments();
        if (KiteListUtils.isNotEmpty(payments) && KiteStringUtils.isNotEmpty(payments.get(0).getInstanceId())) {
            goods.setPaymentInstId(payments.get(0).getInstanceId());
        }
        // 处理SPU相关信息
        if (CuccPosServiceUtils.isRouteUser(context.getSceneInstId(), context.getCustId())) {
            /*if (KiteStringUtils.isEmpty(goods.getParentInstId())) {
                // 基础销售品，通过分类和销售品ID，调用接口找到SPU(系统内部销售品类型为13）
                GoodsDTO promOfferInfo = getPromotionOfferInfo(curOffer.getCateId(), curOffer.getOfferId());
                if (Objects.nonNull(promOfferInfo)) {
                    goods.setSaleGoodsCode(promOfferInfo.getGoodsSku()); //销售商品编码
                    goods.setSaleGoodsName(promOfferInfo.getGoodsName());
                }
                else {
                    BssException
                        .throwOut("订单归集报文组装", "订单归集报文组装", "根据销售品分类【" + curOffer.getCateId() + "】查询SPU信息，未查询到数据，请稍后再试");
                }
            }
            else {
                //附属销售品，采用基础销售品的SPU。
                List<KitePosGoodsDTO> goodsList = context.getPosDto().getGoods();
                KitePosGoodsDTO parentGoods = goodsList.stream()
                    .filter(goodsInst -> KiteStringUtils.isEqual(goods.getParentInstId(), goodsInst.getInstanceId())).findFirst().orElse(null);
                if (Objects.nonNull(parentGoods)) {
                    goods.setSaleGoodsCode(parentGoods.getSaleGoodsCode()); //销售商品编码
                    goods.setSaleGoodsName(parentGoods.getSaleGoodsName());
                }
            }*/
            // 订购初始化，变更还原时保存了saleGoodsCode，saleGoodsName属性
            String saleGoodCode = offerInst.getAttrValue("saleGoodsCode");
            String saleGoodName = offerInst.getAttrValue("saleGoodsName");
            //开启多线程处理,主产品和附加产品由不同线程初始化,附加产品的属性可能为空,从主商品节点取
            if (KiteStringUtils.isAnyEmpty(saleGoodCode, saleGoodName) && KiteStringUtils.isNotEmpty(goods.getParentInstId())) {
                KitePosGoodsDTO mainPosGoodsDTO = context.getPosDto().getGoods().stream()
                    .filter(good -> goods.getParentInstId().equals(good.getInstanceId()))
                    .findAny().orElse(null);
                if (Objects.nonNull(mainPosGoodsDTO)) {
                    saleGoodCode = mainPosGoodsDTO.getSaleGoodsCode();
                    saleGoodName = mainPosGoodsDTO.getSaleGoodsName();
                }
            }

            // 若 saleGoodCode 为空，部分产品提交必填，调接口查询
            if (KiteStringUtils.isEmpty(saleGoodCode)) {
                String cateId = OfferCache.get(offerInst.getOfferId()).getCateId();
                String codea = DcPublicCache.getCodea("2021063001", "saleGoodsCode");
                if (KiteStringUtils.isNotEmpty(codea) && KiteStringUtils.equalsAny(cateId, codea.split(SymbolConsts.COMMA))) {
                    saleGoodCode = goodsService.getPromotionOfferId(offerInst.getOfferId());
                    if (KiteStringUtils.isNotEmpty(saleGoodCode)) {
                        saleGoodName = OfferCache.get(saleGoodCode).getOfferName();
                    }
                }
            }

            goods.setSaleGoodsCode(saleGoodCode);
            goods.setSaleGoodsName(saleGoodName);
        }
        if (KiteStringUtils.isNotEmpty(offerInst.getAttrValue("startDate"))) {
            goods.setStartDate(offerInst.getAttrValue("startDate"));
        }
        if (!ChangeTypeUtils.CHANGE_TYPE_D.equals(goods.getChangeType()) && KiteStringUtils.isNotEmpty(offerInst.getAttrValue("endDate"))) {
            goods.setEndDate(offerInst.getAttrValue("endDate"));
        }

        // 五大双线，收费方资费，设置资费属性的收费单位值=产品属性收费地市
        String chargeCity = getChargeCityFromProductAttr(goods, offerInst);
        if(KiteStringUtils.isNotEmpty(chargeCity)) {
            KiteAttr kiteAttr = offerInst.getAttr("210005009");
            if(Objects.nonNull(kiteAttr)) {
                kiteAttr.setValue(chargeCity);
            }
        }
        goods.setAttrs(this.packageGoodsAttrInfo(context, offerInst));
        //this.addInstanceIdAttr(context.getSceneInstId(), "instanceId", offerInst.getInstId(), goods);
    }

    /**
     * 重提业务,会把工单的goods缓存起来,此处进行匹配,避免重提业务这里把产品的UserInstId更改了,导致附加商品不展示。
     *
     * @param context
     * @param goods
     */
    private void dealUserInstId(KitePosHandlerContext context, KitePosGoodsDTO goods, List<KitePosUserDTO> users) {
        KiteSceneInst kiteSceneInst = querySceneInstService.getSceneInst(context.getSceneInstId());
        String askSource = "";
        if (!KiteObjectUtils.isEmpty(kiteSceneInst)) {
            askSource = kiteSceneInst.getAskSource();
        }
        if (KiteStringUtils.isEmpty(goods.getUserInstId()) && KiteListUtils.isNotEmpty(users) && users.size() > 1
            && KiteStringUtils.isEqual(LocalKeyConsts.ASK_SOURCE_ORDER, askSource)) {
            List<KitePosGoodsDTO> kitePosGoodsList = context.getPosDto().getGoods();
            if (KiteListUtils.isNotEmpty(kitePosGoodsList)) {
                goods.setUserInstId(kitePosGoodsList.stream()
                    .filter(p -> KiteStringUtils.isEqual(goods.getParentInstId(), p.getInstanceId())).findFirst()
                    .map(posGoods -> posGoods.getUserInstId()).orElse(""));
            }
        }
    }

    private void packageGoodsFeeInfo(KitePosHandlerContext context, KitePosGoodsDTO goods, KiteOfferInst offerInst) {
        IQuerySceneInstService querySceneInstService = SpringUtil.getBean(IQuerySceneInstService.class);
        Date createDate = querySceneInstService.getSceneInst(context.getSceneInstId()).getCreateDate();
        String createDateStr = KiteDateUtils.formatDate(createDate, KiteDateUtils.DATE_TIME_FORMAT_14);
        List<KitePosGoodsFeeDTO> fees = new ArrayList<>();
        //根据offerInst查询下一级的可选包
        List<KiteOfferInst> additionalOfferInsts = querySceneInstService
            .listAdditionalOfferInstsFromOfferInst(context.getCustDto().getCustId(), offerInst.getOfferInstId());
        // 删除的资费也需要传到下游
        List<KiteInstChange> instChangeList = querySceneInstService.listInstChanges(context.getSceneInstId(), InstType.ADDITIONAL_OFFER_INST);
        for (KiteInstChange instChange : instChangeList) {
            List<OfferRelInfo> offerRelInfoList = OfferCache.get(offerInst.getOfferId()).listAllOfferRels().stream().filter(offerRelInfo -> {
                return CoreDataOffer.OFF_0005_12.equals(offerRelInfo.getzOfferType()) && StringUtils.equalsAny(offerRelInfo.getRelType(), CoreDataOffer.OFF_0006_100000, CoreDataOffer.OFF_0006_120000);
            }).collect(Collectors.toList());
            KiteOfferInst additionOfferInst = querySceneInstService.getOfferInst(context.getCustDto().getCustId(), instChange.getSubInstId());
            //对于前置环节中新增的资费,场景还原时没有设置变动实例,所以当前场景删除时资费实例动作不会更新为X,这里通过结合originalActionType判断
            if (Objects.nonNull(additionOfferInst) && KiteStringUtils.isEqual(additionOfferInst.getActionType().name(), ActionType.D.name()) && !KiteStringUtils.isEqual(instChange.getOldValue(), ActionType.A.name())) {
                List<OfferRelInfo> filter = offerRelInfoList.stream().filter(offerRelInfo -> KiteStringUtils.isEqual(offerRelInfo.getzOfferId(), additionOfferInst.getOfferId())).collect(Collectors.toList());
                if (KiteListUtils.isNotEmpty(filter)) {
                    additionalOfferInsts.add(additionOfferInst);
                }
            }
        }

        // 获取到该订单新增的趸交资费
        List<KitePosGoodsFeeDTO> resaleFeeList = this.getResaleFeeList(context.getSceneInstId());

        // 五大双线，收费方资费，资费的收费单位属性传产品属性-收费地市
        String chargeCity = getChargeCityFromProductAttr(goods, offerInst);

        List<String> addedInstIds = new ArrayList<>();
        additionalOfferInsts.forEach(additionalInst -> {
            if (addedInstIds.contains(additionalInst.getInstId())) {
                return;
            }
            addedInstIds.add(additionalInst.getInstId());
            Offer additionalOffer = ProdFeeCache.get(additionalInst.getOfferId());
            String offerName = additionalOffer.getOfferName();

            KitePosGoodsFeeDTO fee = new KitePosGoodsFeeDTO();
            fee.setInstanceId(additionalInst.getInstId());
            fee.setCode(additionalInst.getOfferId());
            fee.setFeeName(offerName);
            fee.setChangeType(ChangeTypeUtils.getChangeType(additionalInst.getActionType().name())); //新增
            fee.setType("");
            Map<String, Object> offerMap = additionalOffer.getOfferMap();
            if (KiteMapUtils.isNotEmpty(offerMap)) {
                fee.setType(KiteMapUtils.getString(offerMap, "payType"));  //传入的TYPE
                fee.setDiscntCode(KiteMapUtils.getString(offerMap, "discntCode"));
            }
            fee.setDestItemId(additionalInst.getExtOfferInstId());
            Map<String, KiteAttr> prodAttrMap = setFeeChargeUnit(additionalInst.getAttrMap(), chargeCity);
            fee.setAttrs(this.packageProdAttrInfo(context, prodAttrMap, additionalInst.getInstType(), additionalInst.getInstId(), createDateStr, null));
            // 趸交资费资费实例ID属性，在订购时，销售中心将生成的资费实例ID传给订单中心
            if (KiteListUtils.isNotEmpty(fee.getAttrs()) && LocalKeyConsts.FEE_PAY_TYPE_ONE_OFF.equals(KiteMapUtils.getString(offerMap, "payType")) && ActionType.A.equals(additionalInst.getActionType())) {
                KitePosAttrDTO feeInstIdAttr = fee.getAttrs().stream().filter(feeAttr -> KiteStringUtils.equals(feeAttr.getCode(), "210004688")).findFirst().orElse(null);
                if (Objects.nonNull(feeInstIdAttr)) {
                    feeInstIdAttr.setValue(additionalInst.getInstId());
                } else {
                    feeInstIdAttr = new KitePosAttrDTO();
                    feeInstIdAttr.setCode("210004688");
                    feeInstIdAttr.setValue(additionalInst.getInstId());
                    feeInstIdAttr.setStartDate(createDateStr);
                    feeInstIdAttr.setEndDate(LocalKeyConsts.ATTR_SEND_DATE);
                    feeInstIdAttr.setType("STRING");
                    feeInstIdAttr.setChangeType(ChangeTypeUtils.getChangeType(ActionType.A.name()));
                    fee.getAttrs().add(feeInstIdAttr);
                }
            }
            //this.addInstanceIdAttr(context.getSceneInstId(), "instanceId", additionalInst.getInstId(), fee);
            // 落户老集客时，需要补全ProductDestItemId和OrderDestItemId
            List<KitePosGoodsFeeDTO> KitePosGoodsFeeDTOList = querySceneInstService.getExtParameterValue(context.getSceneInstId(), offerInst.getOfferInstId()+"_oldPosGoodsFeeDto");
            if (KiteListUtils.isNotEmpty(KitePosGoodsFeeDTOList)) {
                KitePosGoodsFeeDTO kitePosGoodsFee = KitePosGoodsFeeDTOList.stream().filter(
                    kitePosGoodsFeeDTO -> KiteStringUtils.equals(fee.getCode(), kitePosGoodsFeeDTO.getCode())
                        && KiteStringUtils.equals(fee.getDestItemId(), kitePosGoodsFeeDTO.getDestItemId()))
                    .findFirst().orElse(null);
                if (!KiteObjectUtils.isEmpty(kitePosGoodsFee)) {
                    fee.setProductDestItemId(
                        KiteStringUtils.isNotEmpty(kitePosGoodsFee.getProductDestItemId()) ?
                            kitePosGoodsFee.getProductDestItemId() : "");
                    fee.setOrderDestItemId(KiteStringUtils.isNotEmpty(kitePosGoodsFee.getOrderDestItemId()) ?
                        kitePosGoodsFee.getOrderDestItemId() : "");
                }
            }
            RecalculateFeeAttrs(offerInst, fee);

            fees.add(fee);
        });
        // 返销时，所有新增的趸交资费失效时间刷新为操作前一天的23：59：59
        dealResaleFeeAttrs(fees, context.getSceneInstId(), resaleFeeList);
        goods.setFees(fees);
    }

    /**
     * 封装附加产品
     *
     * @param context
     * @param goods
     * @param objInstRels
     * @param extOfferInstId
     */
    private void packageAddRoleProductInfo(KitePosHandlerContext context, KitePosGoodsDTO goods, List<KitePosOfferObjInstRelVO> objInstRels, String extOfferInstId) {
        IQuerySceneInstService querySceneInstService = SpringUtil.getBean(IQuerySceneInstService.class);
        Date createDate = querySceneInstService.getSceneInst(context.getSceneInstId()).getCreateDate();
        String createDateStr = KiteDateUtils.formatDate(createDate, KiteDateUtils.DATE_TIME_FORMAT_14);

        List<KitePosProductDTO> products = new ArrayList<>();
        Map<String, KitePosProdInstVO> prodInstMap = context.getPosSceneBO().getProdInstMap();

        String rootInstId = this.querySceneInstService.getSceneInst(context.getSceneInstId()).getRootInstId();
        InstType instType = this.querySceneInstService.getSceneInst(context.getSceneInstId()).getRootInstType();
        KiteInst kiteInst = this.querySceneInstService.getKiteInst(context.getCustId(), instType, rootInstId);
        String cateId = OfferCache.get(kiteInst.getSpecId()).getCateId();
        boolean isDoubleLine = KiteStringUtils.equalsAny(cateId, ProdCateUtil.getDoubleLineCateIdForArr());

        objInstRels.forEach((instRel) -> {
            String instId = instRel.getInstId();
            KitePosProdInstVO prodInstVO = prodInstMap.get(instId);
            KiteProdInst prodInst = querySceneInstService.getProdInst(context.getCustId(), instId);
            if ((Objects.nonNull(prodInstVO) && Objects.nonNull(prodInstVO.getProdInst()))
                // 双线附加商品删除，prodInstVO=null，导致删除goods.product节点为空报错，增加如下判断
                || isDoubleLine && (Objects.nonNull(prodInst) && KiteStringUtils.isEqual(prodInst.getActionType().name(), ActionType.D.name()))) {

                KitePosProductDTO product = null;
                List<KitePosProductDTO> productList = goods.getProducts().stream().filter(pp -> KiteStringUtils.equals(pp.getCode(), prodInst.getProdId())).collect(Collectors.toList());
                if (!KiteListUtils.isEmpty(productList)) {
                    product = productList.get(0);
                }
                if (Objects.isNull(product)) {
                    product = new KitePosProductDTO();

                    //通过BillProdType区分是基础产品还是资费类产品，这里取基础产品
                    Product prodSpec = ProductCache.get(prodInst.getProdId());
                    String prodId = prodInst.getProdId();

                    String prodName = prodSpec.getProdName();
                    String prodType = LocalKeyConsts.PRODUCT_TYPE_ADD;
                    product.setInstanceId(prodInst.getInstId());
                    if (KiteStringUtils.isEmpty(extOfferInstId) && isUserGoods(cateId)) {
                        product.setDestItemId(this.getInstanceId(context.getSceneInstId(), "GOODS_ITEM_ID", context.getCustDto()));
                    } else {
                        product.setDestItemId(extOfferInstId);
                    }
                    if (CuccPosServiceUtils.isRouteUser(context.getSceneInstId(), context.getCustId())) {
                        if (!KiteStringUtils.isEmpty(prodInst.getExtProdInstId())) {
                            product.setDestItemId(prodInst.getExtProdInstId());
                        }
                        product.setProductCate(prodSpec.getProdCatType());
                    }
                    product.setCode(prodId);
                    product.setName(prodName);
                    //product.setAliasName(aliasName);
                    product.setType(prodType);
                    String change = ChangeTypeUtils.getChangeType(prodInst.getActionType().name());
                    if (KiteStringUtils.isEqual(change, ChangeTypeUtils.CHANGE_TYPE_M)) {
                        change = ChangeTypeUtils.CHANGE_TYPE_K;
                    }
                    product.setChangeType(change); //新增
                    //添加品牌、电信类型
                    product.setBrandCode(prodSpec.getBrandCode());
                    product.setServiceTypeCode(prodSpec.getServiceTypeCode());
                }
                // 方式存在多个相同产品的情况
                String oldChangeType = product.getChangeType();
                String newChangeType = ChangeTypeUtils.getChangeType(prodInst.getActionType().name());
                // 特殊处理补充产品的changetype
                if (StringUtils.isNotEmpty(oldChangeType) && !StringUtils.equals(oldChangeType, newChangeType)) {
                    product.setChangeType(ChangeTypeUtils.CHANGE_TYPE_M);
                }
                List<KitePosAttrDTO> kitePosAttrDTOS = product.getAttrs();
                if (KiteListUtils.isEmpty(kitePosAttrDTOS)) {
                    kitePosAttrDTOS = Lists.newArrayList();
                }
                this.packageAddRoleProdAttrInfo(context, kitePosAttrDTOS, prodInst.getAttrMap(), createDateStr, prodInst.getProdInstId(), product.getType(), product.getChangeType(), prodInst.getProdId());
                // 附属产品的功能产品
                List<KitePosAttrDTO> kitePosAddAttrDTOS = addRoleProdFuncAttrInfo(context, kitePosAttrDTOS, prodInst.getProdInstId(), createDateStr);
                //如果功能产品有更新则更新接入产品状态
                if(KiteStringUtils.equals(product.getChangeType(),ChangeTypeUtils.CHANGE_TYPE_K) && KiteListUtils.isNotEmpty(kitePosAddAttrDTOS)){
                    if(kitePosAddAttrDTOS.stream().anyMatch(ss->!KiteStringUtils.equals(ss.getChangeType(),ChangeTypeUtils.CHANGE_TYPE_K))){
                        product.setChangeType(ChangeTypeUtils.CHANGE_TYPE_M);
                    }
                }
                kitePosAttrDTOS.addAll(kitePosAddAttrDTOS);
                // 大数据附加产品 附件处理
                String offerId = "";
                if (KiteStringUtils.isNotEmpty(prodInst.getOfferId())) {
                    offerId = prodInst.getOfferId();
                } else {
                    List<KiteOfferInst> offerInst = querySceneInstService.listMainOfferInstsByProdInstId(context.getCustId(), prodInst.getProdInstId());
                    if (KiteListUtils.isNotEmpty(offerInst)) {
                        offerId = offerInst.get(0).getSpecId();
                    }
                }
                dealAttachementsAttrGrp(prodInst, kitePosAttrDTOS, context, createDateStr, offerId, null);
                product.setAttrs(kitePosAttrDTOS);

                //this.addInstanceIdAttr(context.getSceneInstId(), "instanceId", prodInst.getInstId(), product);
                dealStartDateAndEndDate(context.getSceneInstId(), createDateStr, product);
                products.add(product);
            }
        });

        goods.setProducts(products);
    }

    // 附属商品的功能产品
    private List<KitePosAttrDTO> addRoleProdFuncAttrInfo(KitePosHandlerContext context,List<KitePosAttrDTO> kitePosAttrDTOS, String prodInstId, String createDateStr) {
        List<KitePosAttrDTO> grpAttrs = new ArrayList<>();
        List<KiteProdInstFunc> prodInstFuncs = Lists.newArrayList();
        CuccContextCustDTO custDto = context.getCustDto();
        KiteProdInst prodInst = querySceneInstService.getProdInst(custDto.getCustId(), prodInstId);
        //List<KiteOfferInst> kiteOfferInsts = querySceneInstService.listOfferInstsByProdInstId(custDto.getCustId(), prodInst.getProdInstId());
        prodInstFuncs.addAll(this.querySceneInstService.listProdInstFuncs(custDto.getCustId(), prodInst.getProdInstId()));
        // 获取删除的功能产品
        List<KiteInstChange> instChangeList = querySceneInstService.listInstChanges(context.getSceneInstId(), InstType.PROD_INST_FUNC);
        for (KiteInstChange instChange : instChangeList) {
            if (KiteStringUtils.isEqual(instChange.getNewValue(), ActionType.D.name())) {
                KiteProdInstFunc delProdFuncInst = querySceneInstService.getProdInstFunc(custDto.getCustId(), instChange.getInstId());
                if (Objects.nonNull(delProdFuncInst) && KiteStringUtils.isEqual(delProdFuncInst.getAccProdInstId(), prodInst.getProdInstId())
                    && KiteStringUtils.isEqual(delProdFuncInst.getActionType().name(), ActionType.D.name())) {
                    prodInstFuncs.add(delProdFuncInst);
                }
            }
        }

        Map<String, List<KiteProdInstFunc>> grpProdInstFuncMap = KiteListUtils.groupBy(prodInstFuncs, "specId");
        Iterator<String> it = grpProdInstFuncMap.keySet().iterator();
        while (it.hasNext()) {
            String specIdStr = it.next();
            Product funcProd = ProductCache.get(specIdStr);
            // 将prodNber作为属性组的code
            String specId = funcProd.getProdNbr();
            if (KiteStringUtils.isEmpty(specId)) {
                specId = specIdStr;
            }
            KitePosAttrDTO grpAttr = new KitePosAttrDTO();
            Map<String, Object> grpMap = new HashMap<String, Object>();
            grpAttr.setCode(specId);
            grpAttr.setType(LocalKeyConsts.ATTR_TYPE_GROUP);
            List<KiteProdInstFunc> list = grpProdInstFuncMap.get(specIdStr);
            if (KiteListUtils.isEmpty(list)) {
                continue;
            }
            //特殊处理 配置的功能产品放在主产品节点
            List<DcPublic> spDcs = DcPublicCache.getByPcode("2021102107", specIdStr);
            if(KiteListUtils.isNotEmpty(spDcs)){
                KiteProdInstFunc mainAttrFunc = list.get(0);
                Map<String, KiteAttr> attrMap = mainAttrFunc.getAttrMap();
                Iterator<Map.Entry<String, KiteAttr>> enAttrIt = attrMap.entrySet().iterator();
                while (enAttrIt.hasNext()){
                    KiteAttr kiteAttr = enAttrIt.next().getValue();
                    if(Objects.nonNull(kiteAttr)&&KiteStringUtils.isNotEmpty(kiteAttr.getValue())){
                        KitePosAttrDTO posAttr = genKitePosAttr(kiteAttr, context.getSceneInstId(), prodInst.getInstType(), prodInst.getInstId(), context.getCustId(), createDateStr, context.getIsBcmcFlow());
                        grpAttrs.add(posAttr);
                    }
                }
                continue;
            }
            String grpStartDate = null;
            String grpEndDate = null;
            Map<String, KitePosAttrDTO> attrGroupMap = querySceneInstService.getExtParameterValue(context.getSceneInstId(), "attrGroupMap_".concat(prodInstId));
            if (KiteMapUtils.isNotEmpty(attrGroupMap)) {
                KitePosAttrDTO kitePosAttrDTO = attrGroupMap.get(grpAttr.getCode());
                if (Objects.nonNull(kitePosAttrDTO)) {
                    grpStartDate = kitePosAttrDTO.getStartDate();
                    if (!KiteStringUtils.equals(grpAttr.getChangeType(), ChangeTypeUtils.CHANGE_TYPE_D)) {
                        grpEndDate = kitePosAttrDTO.getEndDate();
                    }
                }
            }

            for (KiteProdInstFunc inst : list) {
                List<KitePosAttrDTO> attrs = new ArrayList<>();
                Map<String, KiteAttr> attrMap = inst.getAttrMap();
                Iterator<String> ait = attrMap.keySet().iterator();
                while (ait.hasNext()) {
                    String fieldName = ait.next();

                    KiteAttr kiteAttr = attrMap.get(fieldName);
                    if (KiteStringUtils.isEmpty(kiteAttr.getValue()) && KiteStringUtils.isEmpty(kiteAttr.getOriginValue())) {
                        continue;
                    }
                    KitePosAttrDTO posAttr = genKitePosAttr(kiteAttr, context.getSceneInstId(), inst.getInstType(), inst.getInstId(), context.getCustId(), createDateStr, context.getIsBcmcFlow());
                    if (!KiteObjectUtils.isEmpty(posAttr)) {
                        attrs.add(posAttr);
                    }
                }
                this.addChangeTypeAttr(attrs, inst.getActionType(), createDateStr, grpStartDate, grpEndDate);
                String attrGroupInstId = this.getAttrGroupInstIdFromProdInstFunc(context, inst.getInstId(), specIdStr, specId);
                grpMap.put(attrGroupInstId, attrs);
            }
            grpAttr.setValue(JSONObject.toJSONString(grpMap));
            grpAttr.setChangeType(prodFuncChangeType(list));
            grpAttr.setStartDate(grpStartDate);
            grpAttr.setEndDate(grpEndDate);
            grpAttrs.add(grpAttr);
        }
        return grpAttrs;
    }

    /**
     * 判断是否走用户中心落户，除物联网定制类、连接类和5grcs走老集客类落户，其他的新接产品都走用户中心落户。
     *
     * @param cateId
     * @return
     */
    private boolean isUserGoods(String cateId) {
        boolean result = false;
        DcPublic dp = DcPublicCache.get("20210207001", cateId);
        if (Objects.nonNull(dp)) {
            result = true;
        }
        return result;
    }

    private void packageProductInfoForGiftGoods(KitePosHandlerContext context, KitePosGoodsDTO goods, String offerInstId, String extOfferInstId) {
        String rootInstId = this.querySceneInstService.getSceneInst(context.getSceneInstId()).getRootInstId();
        InstType instType = this.querySceneInstService.getSceneInst(context.getSceneInstId()).getRootInstType();
        KiteInst kiteInst = this.querySceneInstService.getKiteInst(context.getCustId(), instType, rootInstId);
        String cateId = OfferCache.get(kiteInst.getSpecId()).getCateId();

        IQuerySceneInstService querySceneInstService = SpringUtil.getBean(IQuerySceneInstService.class);
        Date createDate = querySceneInstService.getSceneInst(context.getSceneInstId()).getCreateDate();
        String createDateStr = KiteDateUtils.formatDate(createDate, KiteDateUtils.DATE_TIME_FORMAT_14);

        List<KitePosProductDTO> posProducts = Lists.newArrayList();
        List<KiteProdInst> prodInstList = querySceneInstService.listProdInstsFromOfferInst(context.getCustId(), offerInstId);
        prodInstList.forEach(prodInst -> {
            KitePosProductDTO posProduct = this
                .convertToPosProductDto(context, goods, prodInst, createDateStr, extOfferInstId, cateId);
            if (Objects.nonNull(posProduct)) {
                dealStartDateAndEndDate(context.getSceneInstId(), createDateStr, posProduct);
                posProducts.add(posProduct);
            }
        });
        goods.setProducts(posProducts);
    }

    private void dealStartDateAndEndDate(String sceneInstId, String createDateStr, KitePosProductDTO posProduct) {
        String startDate = "";
        String endDate = "";
        KitePosDTO infOrderDto = ExtOrderInfoCache.get(
            sceneInstId); // 原思路是把产品生失效时间保存在com.iwhalecloud.bss.kite.cucc.service.scene.InitSceneOfferInstService.dealProducts（KiteProdInst）实例中,该对象找不到合适字段保存,避免引起其他问题,暂保守使用此方法.
        if (!KiteObjectUtils.isEmpty(infOrderDto) && KiteListUtils.isNotEmpty(infOrderDto.getGoods())) {
            List<KitePosGoodsDTO> kitePosGoodsList = infOrderDto.getGoods();
            for (KitePosGoodsDTO kitePosGoodsDTO : kitePosGoodsList) {
                if (KiteListUtils.isNotEmpty(kitePosGoodsDTO.getProducts())) {
                    List<KitePosProductDTO> KitePosProductDTOList = kitePosGoodsDTO.getProducts();
                    KitePosProductDTO KitePosProduct = KitePosProductDTOList.stream()
                        .filter(product -> KiteStringUtils.isEqual(product.getCode(), posProduct.getCode())).findFirst()
                        .orElse(null);
                    if (!KiteObjectUtils.isEmpty(KitePosProduct)) {
                        startDate = KiteStringUtils.isNotEmpty(KitePosProduct.getStartDate()) ?
                            KitePosProduct.getStartDate() :
                            "";
                        endDate = KiteStringUtils.isNotEmpty(KitePosProduct.getEndDate()) ?
                            KitePosProduct.getEndDate() :
                            "";

                        break;
                    }
                }
            }
        }

        if (KiteStringUtils.isEmpty(posProduct.getStartDate()) && KiteStringUtils.isNotEmpty(startDate)) {
            posProduct.setStartDate(startDate);
        }
        if (KiteStringUtils.isEmpty(posProduct.getEndDate()) && KiteStringUtils.isNotEmpty(endDate)) {
            posProduct.setEndDate(endDate);
        }
        if (KiteStringUtils.isEmpty(posProduct.getStartDate())) {
            posProduct.setStartDate(createDateStr);
        }
        if (KiteStringUtils.isEmpty(posProduct.getEndDate())) {
            posProduct.setEndDate(LocalKeyConsts.ATTR_SEND_DATE);
        }
        if (KiteStringUtils.isEqual(ChangeTypeUtils.CHANGE_TYPE_D, posProduct.getChangeType())) {
            posProduct.setEndDate(createDateStr);
        }
    }

    private void packageProductInfo(KitePosHandlerContext context, KitePosGoodsDTO goods, List<KitePosOfferObjInstRelVO> objInstRels, String extOfferInstId) {
        IQuerySceneInstService querySceneInstService = SpringUtil.getBean(IQuerySceneInstService.class);
        Date createDate = querySceneInstService.getSceneInst(context.getSceneInstId()).getCreateDate();
        String createDateStr = KiteDateUtils.formatDate(createDate, KiteDateUtils.DATE_TIME_FORMAT_14);

        String rootInstId = this.querySceneInstService.getSceneInst(context.getSceneInstId()).getRootInstId();
        InstType instType = this.querySceneInstService.getSceneInst(context.getSceneInstId()).getRootInstType();
        KiteInst kiteInst = this.querySceneInstService.getKiteInst(context.getCustId(), instType, rootInstId);
        String cateId = OfferCache.get(kiteInst.getSpecId()).getCateId();

        List<KitePosProductDTO> products = new ArrayList<>();
        Map<String, KitePosProdInstVO> prodInstMap = context.getPosSceneBO().getProdInstMap();

        for (KitePosOfferObjInstRelVO instRel : objInstRels) {
            String instId = instRel.getInstId();
            KitePosProdInstVO prodInstVO = prodInstMap.get(instId);
            if (Objects.nonNull(prodInstVO) && Objects.nonNull(prodInstVO.getProdInst())) {
                KiteProdInst prodInst = querySceneInstService.getProdInst(context.getCustId(), instId);
                KitePosProductDTO product = this.convertToPosProductDto(context, goods, prodInst, createDateStr, extOfferInstId, cateId);
                if (Objects.nonNull(product)) {
                    dealStartDateAndEndDate(context.getSceneInstId(), createDateStr, product);
                    products.add(product);
                }
            }
        }
        if (KiteListUtils.isEmpty(objInstRels) && CuccPosServiceUtils.isGoodsModifyScene(context.getSceneInstId())) {
            Iterator<KitePosProdInstVO> iterator = prodInstMap.values().iterator();
            while (iterator.hasNext()) {
                KitePosProdInstVO prodInstVO = iterator.next();
                KiteProdInst prodInst = prodInstVO.getProdInst();
                if (!"D".equals(prodInst.getActionType().name())) {
                    continue;
                }
                KitePosProductDTO product = this.convertToPosProductDto(context, goods, prodInst, createDateStr, extOfferInstId, cateId);
                if (Objects.nonNull(product)) {
                    dealStartDateAndEndDate(context.getSceneInstId(), createDateStr, product);
                    products.add(product);
                }
            }
        }
        goods.setProducts(products);
    }

    private KitePosProductDTO convertToPosProductDto(KitePosHandlerContext context, KitePosGoodsDTO goods, KiteProdInst prodInst, String createDateStr, String extOfferInstId, String cateId) {
        //通过BillProdType区分是基础产品还是资费类产品，这里取基础产品
        KiteSceneInst sceneInst = querySceneInstService.getSceneInst(context.getSceneInstId());
        String serviceOfferId = sceneInst.getServiceOfferId();
        Product prodSpec = ProductCache.get(prodInst.getProdId());
        String prodUseType = prodSpec.getProdUseType();
        // 不封装useType=2000的产品，如资费计划产品是配成了2000
        if (KiteStringUtils.equals(prodUseType, LocalKeyConsts.PROD_USE_TYPE_2000)) {
            return null;
        }

        String prodId = prodInst.getProdId();
        List<String> serviceOfferIdList = querySceneInstService //获取页面勾选的操作类型
            .getExtParameterValue(context.getSceneInstId(), "BUSI_CHANGE_SERVICEOFFERID");
        if (!KiteListUtils.isEmpty(serviceOfferIdList)) {
            if (serviceOfferIdList.contains("1072")) {
                ContractOfferDetailDTO offerDetail = querySceneInstService.getExtParameterValue(context.getSceneInstId(), "CHANGE_OFFER_DETAIL");
                if (Objects.nonNull(offerDetail)) {
                    List<OfferDetail> details = OfferCache.get(offerDetail.getOfferId()).listAccessProdDetail();
                    if (!KiteListUtils.isEmpty(details)) {
                        operateSceneInstService.putExtParameter(context.getSceneInstId(), "OLD_PROD_ID", prodId);
                        prodId = details.get(0).getObjId();
                        prodSpec = ProductCache.get(prodId);
                    }
                }
            }
        }

        String prodName = prodSpec.getProdName();
        String prodFuncType = prodSpec.getProdFuncType();
        String prodType = LocalKeyConsts.PRODUCT_TYPE_BASE;
        Map<String, KiteAttr> prodAttrMap = prodInst.getAttrMap();

        String productCate = prodSpec.getProdCatType();

        // 如果是附加产品取已有的
        KitePosProductDTO product = new KitePosProductDTO();

        if (KeyConsts.PROD_FUNC_TYPE_101.equals(prodFuncType)) {
            product.setInstanceId(prodInst.getInstId());
            if (KiteStringUtils.isEmpty(extOfferInstId) && isUserGoods(cateId)) {
                product.setDestItemId(this.getInstanceId(context.getSceneInstId(), "GOODS_ITEM_ID", context.getCustDto()));
            } else {
                product.setDestItemId(extOfferInstId);
            }
            product.setCode(prodId);
            product.setName(prodName);
            product.setType(prodType);
            if (CuccPosServiceUtils.isRouteUser(context.getSceneInstId(), context.getCustId())) {
                if (!KiteStringUtils.isEmpty(prodInst.getExtProdInstId())) {
                    product.setDestItemId(prodInst.getExtProdInstId());
                }
                product.setProductCate(productCate);
            }
            String change = ChangeTypeUtils.getChangeType(prodInst.getActionType().name());
            if (KiteStringUtils.isEqual(change, ChangeTypeUtils.CHANGE_TYPE_M)) {
                change = ChangeTypeUtils.CHANGE_TYPE_K;
            }
            product.setChangeType(change); //新增

            List<KitePosAttrDTO> kitePosAttrDTOS = Lists.newArrayList();
            addCityInfo(context, prodAttrMap, kitePosAttrDTOS, prodId, "2_0000220", "2_0000221", "2_0000222", "2_0000209", "cityInfoA", createDateStr, prodInst.getActionType().name(), cateId, goods.getCode());
            addCityInfo(context, prodAttrMap, kitePosAttrDTOS, prodId, "2_0000107", "2_0000109", "2_0000111", "2_0000105", "cityInfoZ", createDateStr, prodInst.getActionType().name(), cateId, goods.getCode());
            this.packageAttrGroups(context, kitePosAttrDTOS, prodAttrMap, createDateStr, prodInst.getProdInstId(), prodType, prodInst.getProdId());
            //this.packageAddRoleProdAttrInfo(context.getCustDto(), kitePosAttrDTOS, prodAttrMap, createDateStr, prodInst.getProdInstId(), prodType);
            kitePosAttrDTOS.addAll(this.packageProdAttrInfo(context, prodAttrMap, prodInst.getInstType(), prodInst.getInstId(), createDateStr, cateId));
            //产品下功能产品的属性，物联网的APN，资费计划，通信计划使用功能产品实例实现支撑
            List<KitePosAttrDTO> tempKitePosAttrDTOs = this.packageProdFuncAttrInfo(context, context.getSceneInstId(), goods.getInstanceId(), createDateStr, prodInst.getProdInstId(), kitePosAttrDTOS);
            kitePosAttrDTOS.addAll(tempKitePosAttrDTOs);
            packageEmptyValueAttrInfo(prodAttrMap, kitePosAttrDTOS, createDateStr, cateId);

            // 上海云专线要求在base节点传入属性"goodsSku"
            packageGoodSkuAttrInfo(kitePosAttrDTOS, createDateStr, cateId, goods);

            product.setAttrs(kitePosAttrDTOS);
            //this.addInstanceIdAttr(context.getSceneInstId(), "instanceId", prodInst.getInstId(), product);
            //添加品牌、电信类型
            product.setBrandCode(prodSpec.getBrandCode());
            product.setServiceTypeCode(prodSpec.getServiceTypeCode());
        }
        return product;
    }

    private void packageGoodSkuAttrInfo(List<KitePosAttrDTO> kitePosAttrDTOS, String createDateStr, String cateId, KitePosGoodsDTO goodsDTO) {
        if (!KiteStringUtils.equals(cateId, "2100971")) {
            return;
        }
        KitePosAttrDTO kitePosAttrDTO = kitePosAttrDTOS.stream().filter(attr -> attr.getCode().equals("goodSku")).findAny().orElse(null);
        if (Objects.nonNull(kitePosAttrDTO)) {
            return;
        }
        KitePosAttrDTO attr = new KitePosAttrDTO();
        attr.setCode("goodSku");
        attr.setValue(goodsDTO.getCode());
        attr.setType("STRING");
        attr.setStartDate(createDateStr);
        attr.setEndDate(LocalKeyConsts.ATTR_SEND_DATE);
        attr.setChangeType(ChangeTypeUtils.CHANGE_TYPE_A);
        kitePosAttrDTOS.add(attr);
    }

    private void addCityInfo(KitePosHandlerContext context, Map<String, KiteAttr> prodAttrMap,
                             List<KitePosAttrDTO> attrs, String prodId, String province, String city, String area, String cityo,
                             String attrCode, String createDateStr, String instActionType, String cateId, String offerId) {

        String attrValue = null;
        String originValue = null;
        List<DcPublic> list = DcPublicCache.get("20210719001");
        // 是否五大双线落地方产品
        boolean flag = (list != null) && list.stream().anyMatch(dcPublic -> KiteStringUtils.isEqual(offerId, dcPublic.getCodeb()));
        if(flag) {
            // 五大双线落地产品，2_0000105：城市(Z端)
            KiteAttr cityAttr;
            if("2_0000105".equals(cityo)) {
                cityAttr = prodAttrMap.get(cityo);
            } else {
                // 城市(A端)：不同产品编码不同
                cityAttr = getAnyAttr(prodAttrMap, "2_0000209","2_0000104","210005122");
            }
            if(Objects.nonNull(cityAttr)) {
                LocalCityPlaceAttrHandler localCityPlaceAttrHandler = SpringUtil.getBean(LocalCityPlaceAttrHandler.class);
                if(KiteStringUtils.isNotEmpty(cityAttr.getValueDesc()) && !KiteStringUtils.isEqual(cityAttr.getValue(), cityAttr.getValueDesc())) {
                    attrValue = cityAttr.getValueDesc();
                } else if(KiteStringUtils.isNotEmpty(cityAttr.getValue())) {
                    attrValue = localCityPlaceAttrHandler.getValueDesc(cityAttr, null, cityAttr.getValue(), null);
                }

                if(KiteStringUtils.isEqual(cityAttr.getValue(), cityAttr.getOriginValue())) {
                    originValue = attrValue;
                } else {
                    originValue = localCityPlaceAttrHandler.getValueDesc(cityAttr, null, cityAttr.getOriginValue(), null);
                }
            }
        } else {
            String provinceDesc = Optional.ofNullable(prodAttrMap.get(province)).map(
                kiteAttr -> KiteStringUtils.isNotEmpty(kiteAttr.getValueDesc()) ?
                    kiteAttr.getValueDesc() :
                    LocalAttrHelper.getPlatformRegionName("", kiteAttr.getValue(), "10", prodId)).orElse("");
            String cityDesc = Optional.ofNullable(prodAttrMap.get(city)).map(
                kiteAttr -> KiteStringUtils.isNotEmpty(kiteAttr.getValueDesc()) ?
                    kiteAttr.getValueDesc() :
                    LocalAttrHelper.getPlatformRegionName(prodAttrMap.get(province).getValue(), kiteAttr.getValue(), "20", prodId)).orElse("");
            String areaDesc = Optional.ofNullable(prodAttrMap.get(area)).map(
                kiteAttr -> KiteStringUtils.isNotEmpty(kiteAttr.getValueDesc()) ?
                    kiteAttr.getValueDesc() :
                    LocalAttrHelper.getPlatformRegionName(prodAttrMap.get(city).getValue(), kiteAttr.getValue(), "30", prodId)).orElse("");
            attrValue = KiteStringUtils.joinWith(SymbolConsts.HYPHEN, provinceDesc, cityDesc, areaDesc);
        }
        if (KiteStringUtils.isEmpty(attrValue) || KiteStringUtils.isEqual(attrValue, "--")) {
            return;
        }

        if(!flag) {
            // 上海云专线没有city:2_0000221属性，不做处理
            if (Objects.nonNull(prodAttrMap.get(cityo)) && !KiteStringUtils.equals(cateId, "2100971")) {
                String value = Objects.nonNull(prodAttrMap.get(city)) ? prodAttrMap.get(city).getValue() : "";
                prodAttrMap.get(cityo).setValue(value);
                String attrOriginValue = Objects.nonNull(prodAttrMap.get(city)) ? prodAttrMap.get(city).getOriginValue() : "";
                prodAttrMap.get(cityo).setOriginValue(attrOriginValue);
            }

            String originProvinceDesc = Optional.ofNullable(prodAttrMap.get(province)).map(
                kiteAttr -> LocalAttrHelper.getPlatformRegionName("", kiteAttr.getOriginValue(), "10", prodId)).orElse("");
            String originCityDesc = Optional.ofNullable(prodAttrMap.get(city)).map(
                kiteAttr -> LocalAttrHelper.getPlatformRegionName(prodAttrMap.get(province).getOriginValue(), kiteAttr.getOriginValue(), "20", prodId)).orElse("");
            String originareaDesc = "";
            if (Objects.nonNull(prodAttrMap.get(city))) {
                originareaDesc = Optional.ofNullable(prodAttrMap.get(area)).map(
                    kiteAttr -> LocalAttrHelper.getPlatformRegionName(prodAttrMap.get(city).getOriginValue(), kiteAttr.getOriginValue(), "30", prodId)).orElse("");
            } else {
                originareaDesc = Optional.ofNullable(prodAttrMap.get(area)).map(
                    kiteAttr -> LocalAttrHelper.getPlatformRegionName("", kiteAttr.getOriginValue(), "30", prodId)).orElse("");
            }
            originValue = KiteStringUtils.joinWith(SymbolConsts.HYPHEN, originProvinceDesc, originCityDesc, originareaDesc);
        }

        KitePosAttrDTO attr = new KitePosAttrDTO();
        attr.setCode(attrCode);
        attr.setValue(attrValue);
        attr.setType("STRING");
        attr.setStartDate(createDateStr);
        attr.setEndDate(LocalKeyConsts.ATTR_SEND_DATE);
        if (KiteStringUtils.isEqual(ActionType.M.name(), instActionType) &&
            KiteStringUtils.isEqual(attrValue, originValue)) {
            attr.setChangeType(ChangeTypeUtils.CHANGE_TYPE_K);
        } else {
            attr.setChangeType(ChangeTypeUtils.getChangeType(instActionType));
        }
        if (!KiteStringUtils.isEqual(attr.getChangeType(), ChangeTypeUtils.CHANGE_TYPE_A)) {
            if (KiteStringUtils.isNotEmpty(originValue) && !KiteStringUtils.isEqual(originValue, "--")) {
                attr.setOriginValue(originValue);
            }
        }
        attrs.add(attr);
    }

    private static KiteAttr getAnyAttr(Map<String, KiteAttr> attrMap, String ...fieldNames) {
        for (String fieldName : fieldNames) {
            if(attrMap.containsKey(fieldName)) {
                return attrMap.get(fieldName);
            }
        }
        return null;
    }

    private void packageEmptyValueAttrInfo(Map<String, KiteAttr> prodAttrMap,
                                           List<KitePosAttrDTO> attrs, String createDateStr, String cateId) {
        String fieldNames = DcPublicCache.getCodea("20210227", cateId);
        if (KiteStringUtils.isEmpty(fieldNames)) {
            return;
        }
        Arrays.stream(fieldNames.split(",")).forEach(fieldName -> {
            KitePosAttrDTO kitePosAttrDTO = attrs.stream().filter(attr -> attr.getCode().equals(fieldName)).findAny().orElse(null);
            if (Objects.nonNull(kitePosAttrDTO)) {
                return;
            }
            KitePosAttrDTO attr = new KitePosAttrDTO();

            attr.setCode(fieldName);
            attr.setValue("");
            attr.setType("STRING");
            attr.setStartDate(createDateStr);
            attr.setEndDate(LocalKeyConsts.ATTR_SEND_DATE);
            attr.setChangeType(ChangeTypeUtils.CHANGE_TYPE_A);
            attrs.add(attr);
        });
    }

    private List<KitePosAttrDTO> packageProdAttrInfo(KitePosHandlerContext context, Map<String, KiteAttr> prodAttrMap, InstType instType, String instId, String createDateStr, String categoryId) {
        List<KitePosAttrDTO> attrs = new ArrayList<>();
        //CuccContextCustDTO custDto = context.getCustDto();
        //个人客户需要将数据传给后端 上海极简个人需求，这里不需要 add by sqy 20210208
        //this.addCustTypeAttr(attrs, custDto, instActionType, createDateStr);
        if (Objects.isNull(prodAttrMap) || prodAttrMap.isEmpty()) {
            return attrs;
        }

        List<String> fileNameList = new ArrayList<>();
        // 获取页面勾选的操作类型
        List<String> serviceOfferIdList = querySceneInstService.getExtParameterValue(context.getSceneInstId(), "BUSI_CHANGE_SERVICEOFFERID");
        // 取消弹性升速，接口chengeType传删除（1）
        if (KiteListUtils.isNotEmpty(serviceOfferIdList) && serviceOfferIdList.contains("1052") && KiteStringUtils.isNotEmpty(categoryId)) {
            List<ServiceControlScope> elasticAttrs = ServiceControlScopeCache.get("1051" + SymbolConsts.HYPHEN + categoryId);
            elasticAttrs.forEach(serviceControlScope -> fileNameList.add(serviceControlScope.getFieldName()));
        }

        Iterator<KiteAttr> iterator = prodAttrMap.values().iterator();
        while (iterator.hasNext()) {
            KiteAttr kiteAttr = iterator.next();
            // 资费-标准月租，为空也需要传
            if(!KiteStringUtils.isEqual(kiteAttr.getFieldName(), LocalKeyConsts.STANDARD_MONTHLY_RENT)) {
                // 原始值不为空，新值为空时，属性需要传给外围系统
                if ("98H".equals(kiteAttr.getAttrValueTypeId()) || (KiteStringUtils.isEmpty(kiteAttr.getValue()) && KiteStringUtils.isEmpty(kiteAttr.getOriginValue()))) {
                    continue;
                }
            }
            if (KiteStringUtils.equals(kiteAttr.getValue(), kiteAttr.getOriginValue())&&KiteListUtils.isNotEmpty(serviceOfferIdList) && serviceOfferIdList.size() > 1) {
                List<DcPublic> dc = DcPublicCache.getByPkey("2022040616", categoryId);
                String fieldName = dc.stream().map(DcPublic::getCodea).collect(Collectors.joining(","));
                if(fieldName.contains(kiteAttr.getFieldName())){
                    //精品网产品变更AZ端口类型特殊处理
                    AtomicBoolean haven = new AtomicBoolean(false);
                    serviceOfferIdList.removeIf(serviceOfferId->{
                        List<DcPublic> dcPublics = DcPublicCache.getByPcode("2022040616", categoryId,serviceOfferId);
                        if(null!=dcPublics&&dcPublics.size()>0){
                            dcPublics.forEach(d->{
                                if(d.getCodea().contains(kiteAttr.getFieldName())){
                                    haven.set(true);
                                };
                            });
                        }
                        return haven.get();
                    });
                    context.getPosDto().getOrder().setBizType(serviceOfferIdList.stream().collect(Collectors.joining(",")));
                }
            }
            KitePosAttrDTO posAttr = genKitePosAttr(kiteAttr, context.getSceneInstId(), instType, instId, context.getCustId(), createDateStr, context.getIsBcmcFlow());
            if (!KiteObjectUtils.isEmpty(posAttr)) {

                if (fileNameList.contains(posAttr.getCode())) {
                    // 取消弹性升速，接口chengeType传删除（1）
                    posAttr.setChangeType(ChangeTypeUtils.CHANGE_TYPE_D);
                    posAttr.setEndDate(createDateStr);
                }
//              全程要求完成时间精确到分的补00
                if( LocalKeyConsts.REQUIRED_FINISH_TIME.contains(posAttr.getCode())){
                    posAttr.setValue(posAttr.getValue().length()==16?(posAttr.getValue()+DateUtils.SECOND):posAttr.getValue());
                }
                attrs.add(posAttr);
            }
        }
        return attrs;
    }

    private KitePosAttrDTO genKitePosAttr(KiteAttr kiteAttr, String sceneInstId, InstType instType, String instId, String custId, String createDateStr, boolean isBcmcFlow) {
        KiteSceneInst sceneInst = querySceneInstService.getSceneInst(sceneInstId);
        String serviceOfferId = sceneInst.getServiceOfferId();
        //联动隐藏的属性不传到下游系统
        if (KiteStringUtils.equals(kiteAttr.getShowType(), KeyConsts.PROD_ATTR_SHOW_TYPE_E)) {
            if (KiteStringUtils.isIndexOf(skipFlowService, serviceOfferId, ",")) {
                return null;
            } else {
                // 除产品变更外,通过onShow方法实现的联动展示逻辑在其他二次类业务中都不触发,如果不送,再做变更时就丢失了,这里把原值送下去
                if (KiteStringUtils.isAllEmpty(kiteAttr.getOriginValue(), kiteAttr.getValue())
                    || !KiteStringUtils.isEqual(kiteAttr.getOriginValue(), kiteAttr.getValue())) {
                    return null;
                }
            }
        }

        KiteInst kiteInst = this.querySceneInstService.getKiteInst(custId, instType, instId);
        ActionType actionType = kiteInst.getActionType();
        KitePosAttrDTO attr = new KitePosAttrDTO();
        attr.setCode(kiteAttr.getFieldName());
        attr.setType("STRING");
        attr.setStartDate(Optional.ofNullable(kiteAttr.getStartDate()).orElse(createDateStr));
        attr.setEndDate(Optional.ofNullable(kiteAttr.getEndDate()).orElse(LocalKeyConsts.ATTR_SEND_DATE));
        attr.setValue(getAttrValue(kiteAttr));

        // PCRF附件的初值为attachmentUrl，提前set值，PCRF附件取第一个的URL，确保changeType正确
        if ("200004167".equals(kiteAttr.getFieldName()) && !KiteStringUtils.isEmpty(kiteAttr.getValue())) {
            JSONArray arrs = JSONArray.parseArray(kiteAttr.getValue());
            JSONObject obj = (JSONObject) arrs.get(0);
            String url = (String) obj.get("attachmentUrl");
            attr.setValue(url);
        }

        if (!KiteStringUtils.equals(kiteAttr.getInstType().name(), InstType.MAIN_OFFER_INST.name())) {
            //实例是M，属性新旧值相等传K
            if (KiteStringUtils.equals(actionType.name(), ActionType.M.name())
                && KiteStringUtils.equals(attr.getValue(), kiteAttr.getOriginValue())) {
                attr.setChangeType(ChangeTypeUtils.getChangeType(ActionType.K.name()));
            } else if (KiteStringUtils.equalsAny(actionType.name(), ActionType.A.name(), ActionType.D.name())) {
                attr.setChangeType(ChangeTypeUtils.getChangeType(actionType.name()));
            } else if (KiteStringUtils.equalsAny(actionType.name(), ActionType.C.name())) {
                //实例动作为C时，属性传删除，这个主要是资费产品
                attr.setChangeType(ChangeTypeUtils.getChangeType(ActionType.D.name()));
            } else if (KiteStringUtils.isEmpty(attr.getValue()) && KiteStringUtils.isNotEmpty(kiteAttr.getOriginValue())) {
                // 新值为空，原值不为空，传删除, 并且当前值要送成原值
                attr.setChangeType(ChangeTypeUtils.getChangeType(ActionType.D.name()));
                attr.setValue(kiteAttr.getOriginValue());
            } else if (KiteStringUtils.isNotEmpty(attr.getValue()) && KiteStringUtils.isEmpty(kiteAttr.getOriginValue())) {
                // 新值不为空，原值为空
                if (KiteStringUtils.equals("200000106", kiteAttr.getFieldName()) || KiteStringUtils.equals("200000175", kiteAttr.getFieldName())
                    || KiteStringUtils.equals("200000185", kiteAttr.getFieldName())) {
                    attr.setChangeType(ChangeTypeUtils.getChangeType(ActionType.K.name()));
                } else {
                    attr.setChangeType(ChangeTypeUtils.getChangeType(ActionType.A.name()));
                }

            } else if (!KiteStringUtils.isEqual(attr.getValue(), kiteAttr.getOriginValue())) {
                // 新增和原值不相等，传修改
                attr.setChangeType(ChangeTypeUtils.getChangeType(ActionType.M.name()));
            } else {
                attr.setChangeType(ChangeTypeUtils.getChangeType(actionType.name()));
            }
        }
        // 属性为新增，不setOriginValue
        if (!KiteStringUtils.isEqual(attr.getChangeType(), ChangeTypeUtils.CHANGE_TYPE_A)) {
            attr.setOriginValue(kiteAttr.getOriginValue());
            if (KiteStringUtils.equals("200000106", kiteAttr.getFieldName()) || KiteStringUtils.equals("200000175", kiteAttr.getFieldName())
                || KiteStringUtils.equals("200000185", kiteAttr.getFieldName())) {
                attr.setOriginValue(attr.getValue());
            }
        }

        if (KiteStringUtils.isEqual(attr.getChangeType(), ChangeTypeUtils.CHANGE_TYPE_D)) {
            // 属性删除时，需要把结束时间修改为当前时间
            attr.setEndDate(createDateStr);
        }

        if (isBcmcFlow) {
            attr.setCname(kiteAttr.getCname());
        }
        // 资费信息属性部分有默认值，修改属性后需要用修改后的属性
        if (KiteStringUtils.isNotEmpty(kiteAttr.getValue()) && InstType.ADDITIONAL_OFFER_INST
            .equals(kiteAttr.getInstType())) {
            attr.setValue(Optional.ofNullable(kiteAttr.getValue()).orElse(""));
        }
        //设置生失效时间 -- 资费信息不需要设置
        if ("200000172".equals(kiteAttr.getFieldName()) && !InstType.ADDITIONAL_OFFER_INST
            .equals(kiteAttr.getInstType())) {
            attr.setValue(DateUtils.formatDate(DateUtils.getStartOfDay(), DateUtils.DEFAULT_PATTERN));
        }
        if ("200000173".equals(kiteAttr.getFieldName()) && !InstType.ADDITIONAL_OFFER_INST
            .equals(kiteAttr.getInstType())) {
            attr.setValue(DateUtils.formatDate(DateUtils.getEndOfDay(), DateUtils.DEFAULT_PATTERN));
        }
        //删除的资费需要设置失效时间属性值为当前时间
        if (ChangeTypeUtils.CHANGE_TYPE_D.equals(attr.getChangeType()) && "200000173".equals(kiteAttr.getFieldName())
            && InstType.ADDITIONAL_OFFER_INST.equals(kiteAttr.getInstType())) {
            attr.setValue(DateUtils.formatDate(sceneInst.getCreateDate(), DateUtils.DEFAULT_PATTERN));
        }
        // 将A/Z端公共属性值替换回产品属性值
        if ("2_0000122".equals(kiteAttr.getFieldName())) {
            // 获取加急，延期公共属性模块的值
            KiteAttr aCommAttr = querySceneInstService.getCommonAttr(sceneInstId, LocalKeyConsts.REPLACE_A);
            if (Objects.nonNull(aCommAttr)) {
                attr.setValue(aCommAttr.getValue());
            }
        }
        if ("2_0000123".equals(kiteAttr.getFieldName())) {
            // 获取加急，延期公共属性模块的值
            KiteAttr aCommAttr = querySceneInstService.getCommonAttr(sceneInstId, LocalKeyConsts.REPLACE_Z);
            if (Objects.nonNull(aCommAttr)) {
                attr.setValue(aCommAttr.getValue());
            }
        }
        String cateId = Optional.ofNullable(ProductCache.get(kiteInst.getSpecId())).map(Product::getCateId).orElse(null);
        if (KiteStringUtils.isEqual(kiteAttr.getFieldName(), "200001615") && KiteStringUtils.isEqual(cateId, "2101120")) {
            // SDWAN-站点详细地址，value为编码，接口需传中文名称
            if (KiteStringUtils.isNotEmpty(kiteAttr.getValueDesc())) {
                attr.setValue(kiteAttr.getValueDesc());
            }
        }
        //大数据产品时间拼接
        if (KiteStringUtils.equals("210004448", kiteAttr.getFieldName()) || KiteStringUtils.equals("210004449", kiteAttr.getFieldName())) {
            String value = kiteAttr.getValue().replace("-", "");
            //付费和销户不需要在拼接
            if (!KiteStringUtils.equals("1069", serviceOfferId) && !KiteStringUtils.equals("1005", serviceOfferId)) {
                if (KiteStringUtils.equals("210004448", kiteAttr.getFieldName())) {
                    value += "000000";
                } else {
                    value += "235959";
                }
            }
            attr.setValue(value);
        }
        return attr;
    }

    /**
     * 为了实现展示方式而加的属性分组，此分组并不在产商品侧配置，无需按属性转传到下游系统
     *
     * @param groupId
     * @return
     */
    private boolean isFakeGroup(String groupId) {
        return !KiteObjectUtils.isEmpty(DcPublicCache.get("20201207002", groupId));
    }

    private List<KiteAttr> attrMapToList(Map<String, KiteAttr> prodAttrMap) {
        List<KiteAttr> prodAttrs = Lists.newArrayList();
        Iterator<String> ii = prodAttrMap.keySet().iterator();
        while (ii.hasNext()) {
            String key = ii.next();
            String groupId = prodAttrMap.get(key).getGroupId();
            if (isFakeGroup(groupId) && !DcPublicCache.getPCode("20201207002", groupId).contains("G")) {
                prodAttrMap.get(key).setGroupId("");
                prodAttrMap.get(key).setGroupName("");
            }
            prodAttrs.add(prodAttrMap.get(key));
            // 移除属性组属性
            if (!KiteStringUtils.isEmpty(groupId) && !DcPublicCache.getPCode("20201207002", groupId).contains("A")) {
                ii.remove();
            }
        }
        return prodAttrs;
    }

    @SuppressWarnings("unchecked")
    private void packageAttrGroups(KitePosHandlerContext context, List<KitePosAttrDTO> kitePosAttrDTOS, Map<String, KiteAttr> prodAttrMap, String createDateStr, String prodInstId, String prodType, String prodId) {
        KiteProdInst prodInst = this.querySceneInstService.getProdInst(context.getCustId(), prodInstId);
        String serviceOfferId = this.querySceneInstService.getSceneInst(context.getSceneInstId()).getServiceOfferId();
        String aPostponeProdId = DcPublicCache.getPCode("20210326001", "postponeProdId");
        List<KiteAttr> prodAttrs = this.attrMapToList(prodAttrMap);
        // 根据属性里面IsSendBill配置为F的，表示不送到订单中心，
        prodAttrs.removeIf(prodAttr -> {
            ProdAttr attrCache = ProdAttrCache.getByAttrName(prodId, prodAttr.getFieldName());
            if (Objects.nonNull(attrCache) && KiteStringUtils.isEqual(attrCache.getIsSendBill(), KeyConsts.IFTRUE_F)) {
                return true;
            }
            return false;
        });
        List<KiteAttr> prodGrpAttrs = prodAttrs.stream().filter(attr -> !KiteStringUtils.isEmpty(attr.getGroupId())).collect(Collectors.toList());
        Map<String, List<KiteAttr>> grpListAttr = KiteListUtils.groupBy(prodGrpAttrs, "groupId");
        if (!KiteListUtils.isEmpty(prodGrpAttrs)) {
            Iterator<String> it = grpListAttr.keySet().iterator();
            while (it.hasNext()) {
                KitePosAttrDTO grpAttr = new KitePosAttrDTO();
                Map<String, Object> grpMap = new HashMap<String, Object>();
                String key = it.next();
                // 如果已经使用功能产品支撑，
                Product product = ProductCache.get(key);
                if (!KiteObjectUtils.isEmpty(product)) {
                    continue;
                }
                List<KiteProdInstFunc> prodInstFuncs = this.querySceneInstService.listProdInstFuncsByProdId(context.getSceneInstId(), key);
                if (!KiteListUtils.isEmpty(prodInstFuncs)) {
                    continue;
                }
                //变更业务延期时，延期组属性已用功能产品还原，这里跳过
                if (KiteStringUtils.equals(key, aPostponeProdId) && KiteStringUtils.isEqual(LocalServiceOfferConsts.SERVICE_OFFER_DELAY, serviceOfferId)) {
                    continue;
                }
                KitePosAttrDTO grpAttr1 = null;
                //取相同code的属性组
                List<KitePosAttrDTO> grpAttrs1 = kitePosAttrDTOS.stream().filter(attr -> KiteStringUtils.equals(key, attr.getCode())).collect(Collectors.toList());
                if (!KiteListUtils.isEmpty(grpAttrs1)) {
                    grpAttr1 = grpAttrs1.get(0);
                }
                if (Objects.nonNull(grpAttr1)) {
                    grpAttr = grpAttr1;
                    grpMap = JSONObject.parseObject(grpAttr1.getValue(), Map.class);
                    //移走已添加的属性组，待添加属性组实例后再设置
                    kitePosAttrDTOS.removeIf(attr -> KiteStringUtils.equals(key, attr.getCode()));
                }
                String groupId = DcPublicCache.getPCode(LocalDcPublicConsts.ATTR_CODE, key);
                if (!KiteStringUtils.isEmpty(groupId)) {
                    grpAttr.setCode(groupId);
                } else {
                    grpAttr.setCode(key);
                }
                grpAttr.setType(LocalKeyConsts.ATTR_TYPE_GROUP);

                String grpStartDate = null;
                String grpEndDate = null;
                Map<String, KitePosAttrDTO> attrGroupMap = querySceneInstService.getExtParameterValue(context.getSceneInstId(), "attrGroupMap_".concat(prodInstId));
                if (KiteMapUtils.isNotEmpty(attrGroupMap)) {
                    KitePosAttrDTO kitePosAttrDTO = attrGroupMap.get(grpAttr.getCode());
                    if (Objects.nonNull(kitePosAttrDTO)) {
                        grpStartDate = kitePosAttrDTO.getStartDate();
                        grpEndDate = kitePosAttrDTO.getEndDate();
                    }
                }

                List<KiteAttr> grpAttrList = (List<KiteAttr>) grpListAttr.get(key);

                List<KitePosAttrDTO> attrs = new ArrayList<>();
                for (KiteAttr kiteAttr : grpAttrList) {
                    if (KiteStringUtils.isEmpty(kiteAttr.getValue())) {
                        continue;
                    }
                    KitePosAttrDTO posAttr = genKitePosAttr(kiteAttr, context.getSceneInstId(), prodInst.getInstType(), prodInst.getInstId(), context.getCustId(), createDateStr, context.getIsBcmcFlow());
                    if (!KiteObjectUtils.isEmpty(posAttr)) {
                        attrs.add(posAttr);
                    }
                }
                if (!KiteListUtils.isEmpty(attrs)) {
                    if("ATTR_GROUP".equals(grpAttr.getType())){
                        boolean flag= attrs.stream().anyMatch(t -> !KiteStringUtils.equals(t.getOriginValue(), t.getValue()));
                        this.addChangeTypeAttr(attrs, !flag&&"M".equals(prodInst.getActionType().name())?ActionType.K:prodInst.getActionType(), createDateStr, grpStartDate, grpEndDate);
                        String attrGroupInstId = this.getAttrGroupInstIdFromProdInst(context, prodInstId, grpAttr.getCode());
                        grpMap.put(attrGroupInstId, attrs);
                        grpAttr.setValue(JSONObject.toJSONString(grpMap));
                        grpAttr.setChangeType(!flag&&"M".equals(prodInst.getActionType().name())?ChangeTypeUtils.CHANGE_TYPE_K:this.getAttrGrpChangeType(context.getCustId(), prodInstId));
                        grpAttr.setStartDate(grpStartDate);
                        grpAttr.setEndDate(grpEndDate);
                        kitePosAttrDTOS.add(grpAttr);
                    }else{
                        this.addChangeTypeAttr(attrs, prodInst.getActionType(), createDateStr, grpStartDate, grpEndDate);
                        String attrGroupInstId = this.getAttrGroupInstIdFromProdInst(context, prodInstId, grpAttr.getCode());
                        grpMap.put(attrGroupInstId, attrs);
                        grpAttr.setValue(JSONObject.toJSONString(grpMap));
                        grpAttr.setChangeType(this.getAttrGrpChangeType(context.getCustId(), prodInstId));
                        grpAttr.setStartDate(grpStartDate);
                        grpAttr.setEndDate(grpEndDate);
                        kitePosAttrDTOS.add(grpAttr);
                    }
                }
            }
        }
    }

    /**
     * 属性组实例ID
     *
     * @param context
     * @param prodInstId
     * @return
     */
    private String getAttrGroupInstIdFromProdInst(KitePosHandlerContext context, String prodInstId, String groupId) {
        String sceneInstId = context.getSceneInstId();
        CuccContextCustDTO custDTO = context.getCustDto();

        // 先从实例中获取，如果是变更或者订单修改等，场景还原时会把属性组实例ID保存到实例的扩展参数中
        String attrGroupInstId = null;
        KiteInst kiteInst = this.querySceneInstService.getKiteInst(context.getCustId(), InstType.PROD_INST, prodInstId);
        if (!KiteObjectUtils.isEmpty(kiteInst)) {
            // 兼容附加产品，附加产品的没有属性组，但是以属性组形式传递
            KiteAttr attr = Optional.ofNullable(kiteInst.getAttr(LocalKeyConsts.PREFIX_ATTR_GROUP_INST_ID + groupId)).orElse(kiteInst.getAttr(LocalKeyConsts.PREFIX_ATTR_GROUP_INST_ID + kiteInst.getSpecId()));
            //attrGroupInstId = Optional
            //    .ofNullable(kiteInst.getExtParamValue(LocalKeyConsts.PREFIX_ATTR_GROUP_INST_ID + groupId))
            //    .orElse(kiteInst.getExtParamValue(LocalKeyConsts.PREFIX_ATTR_GROUP_INST_ID + kiteInst.getSpecId()));
            if (!KiteObjectUtils.isEmpty(attr)) {
                attrGroupInstId = attr.getValue();
            }
        }
        if (!KiteStringUtils.isEmpty(attrGroupInstId)) {
            return attrGroupInstId;
        }
        // 生成新的属性组实例ID
        Map<String, String> inParam = new HashMap<>();
        inParam.put("SEQ_TYPE", "SERVICE_ATTR_GROUP_ITEM_ID");
        inParam.put("SYS_TYPE", "1");
        inParam.put("SYS_SOURCE", "");
        return LocalQuerySeqHelper.getSeqBySeqType(inParam, sceneInstId, prodInstId, custDTO);
    }

    /**
     * 属性组实例ID
     *
     * @param context
     * @param prodInstId
     * @return
     */
    private String getAttrGroupInstIdFromProdInstFunc(KitePosHandlerContext context, String prodInstId, String bfGroupId, String afGroupId) {
        String sceneInstId = context.getSceneInstId();
        CuccContextCustDTO custDTO = context.getCustDto();

        // 先从实例中获取，如果是变更或者订单修改等，场景还原时会把属性组实例ID保存到实例的扩展参数中
        String attrGroupInstId = null;
        KiteProdInstFunc kiteInst = this.querySceneInstService.getKiteInst(context.getCustId(), InstType.PROD_INST_FUNC, prodInstId);
        if (!KiteObjectUtils.isEmpty(kiteInst)) {
            //attrGroupInstId = kiteInst.getExtParamValue(LocalKeyConsts.PREFIX_ATTR_GROUP_INST_ID + groupId);
            KiteAttr attr = kiteInst.getAttr(LocalKeyConsts.PREFIX_ATTR_GROUP_INST_ID + bfGroupId);
            if (KiteObjectUtils.isEmpty(attr)) {
                attr = kiteInst.getAttr(LocalKeyConsts.PREFIX_ATTR_GROUP_INST_ID + afGroupId);
            }
            if (!KiteObjectUtils.isEmpty(attr)) {
                attrGroupInstId = attr.getValue();
            }
        }
        if (!KiteStringUtils.isEmpty(attrGroupInstId)) {
            return attrGroupInstId;
        }
        String accProdInstId = kiteInst.getAccProdInstId();
        // 生成新的属性组实例ID
        Map<String, String> inParam = new HashMap<>();
        inParam.put("SEQ_TYPE", "SERVICE_ATTR_GROUP_ITEM_ID");
        inParam.put("SYS_TYPE", "1");
        inParam.put("SYS_SOURCE", "");
        return LocalQuerySeqHelper.getSeqBySeqType(inParam, sceneInstId, accProdInstId, custDTO);
    }

    /**
     * 获取非重复订购的属性组的动作类型
     *
     * @param custId
     * @param prodInstId
     * @return
     */
    private String getAttrGrpChangeType(String custId, String prodInstId) {
        KiteProdInst prodInst = this.querySceneInstService.getProdInst(custId, prodInstId);
        return ChangeTypeUtils.getChangeType(prodInst.getActionType().name());
    }

    private void packageAddRoleProdAttrInfo(KitePosHandlerContext context, List<KitePosAttrDTO> kitePosAttrDTOS, Map<String, KiteAttr> prodAttrMap, String createDateStr, String prodInstId, String prodType, String prodChangeType, String prodId) {
        this.packageAttrGroups(context, kitePosAttrDTOS, prodAttrMap, createDateStr, prodInstId, prodType, prodId);
        List<KiteAttr> prodAttrs = this.attrMapToList(prodAttrMap);
        KiteProdInst prodInst = this.querySceneInstService.getProdInst(context.getCustId(), prodInstId);
        //非分组属性
        prodAttrs.forEach(kiteAttr -> {
            String fieldName = kiteAttr.getFieldName();
            //对产品编码，服务编码，包编码进行处理
            if (KiteStringUtils.equalsAny(fieldName, "200000106", "200000175", "200000185") && KiteStringUtils.isEmpty(kiteAttr.getValue())) {
                kiteAttr.setValue(kiteAttr.getDefaultValue());
                kiteAttr.setInstId(prodInstId);
            }

            // 排除已存在的属性
            if (!KiteStringUtils.isEmpty(kiteAttr.getValue()) && !kitePosAttrDTOS.stream().anyMatch(attr -> KiteStringUtils.equals(attr.getCode(), kiteAttr.getFieldName()))) {
                KitePosAttrDTO posAttr = genKitePosAttr(kiteAttr, context.getSceneInstId(), prodInst.getInstType(), prodInst.getInstId(), context.getCustId(), createDateStr, context.getIsBcmcFlow());
                if (!KiteObjectUtils.isEmpty(posAttr)) {
                    kitePosAttrDTOS.add(posAttr);
                }
            } else {
                //主要兼容补充通信产品是多个实例的问题
                KitePosAttrDTO posAttr = kitePosAttrDTOS.stream().filter(attr -> KiteStringUtils.equals(attr.getCode(), kiteAttr.getFieldName())).findFirst().orElse(null);
                if (Objects.nonNull(posAttr)) {
                    if (KiteStringUtils.equals(prodChangeType, ChangeTypeUtils.CHANGE_TYPE_M)
                        && KiteStringUtils.equals(posAttr.getValue(), posAttr.getOriginValue())) {
                        posAttr.setChangeType(ChangeTypeUtils.CHANGE_TYPE_K);
                    }
                }
            }
        });
    }

    private List<KitePosAttrDTO> packageProdFuncAttrInfo(KitePosHandlerContext context, String sceneInstId, String offerInstId, String createDateStr, String prodInstId, List<KitePosAttrDTO> kitePosAttrDTOS) {
        List<KitePosAttrDTO> grpAttrs = new ArrayList<>();
        List<KiteProdInstFunc> prodInstFuncs = Lists.newArrayList();
        KiteProdInst mainProdInst = null;
        CuccContextCustDTO custDto = context.getCustDto();
        KiteOfferInst offerInst = this.querySceneInstService.getOfferInst(custDto.getCustId(), offerInstId);
        KiteAttr cateIdAttr = Optional.ofNullable(offerInst.getAttr("cateId")).orElse(null);
        String nodeCode = querySceneInstService.getExtParameterValue(sceneInstId, "nodeCode");
        List<KiteProdInst> mainProdInsts = this.querySceneInstService.listProdInstsFromOfferInst(custDto.getCustId(), offerInstId);
        mainProdInsts = mainProdInsts.stream()
            .filter(prodInst -> !LocalKeyConsts.PROD_USE_TYPE_2000
                .equals(ProductCache.get(prodInst.getSpecId()).getProdUseType())
                && !GoodsInfoTransfer.isAddRoleOffer(offerInst.getSpecId(),
                ProductCache.get(prodInst.getSpecId()).getCateId()))
            .collect(Collectors.toList());
        if (!KiteListUtils.isEmpty(mainProdInsts)) {
            mainProdInst = mainProdInsts.get(0);
        }
        //List<KiteProdInstFunc> prodInstFuncs = this.querySceneInstService.listProdInstFuncs(custDto.getCustId(), mainProdInstId);
        // 取主产品外其他接入产品的功能产品，需排除附加产品
        List<KiteProdInst> kiteProdInsts = this.querySceneInstService.listProdInstsFromOfferInst(custDto.getCustId(), offerInstId);
        for (KiteProdInst prodInst : kiteProdInsts) {
            if (ActionType.X.name().equals(prodInst.getActionType().name())) {
                continue;
            }
            KiteOfferInst offerInstt = this.querySceneInstService.getMainOfferInstByProdInstId(custDto.getCustId(), prodInst.getProdInstId());
            if (KiteObjectUtils.isEmpty(offerInstt)) {
                offerInstt = this.querySceneInstService.getMemOfferInstByProdInstId(custDto.getCustId(), prodInst.getProdInstId());
            }
            if (KiteObjectUtils.isEmpty(offerInstt)) {
                offerInstt = this.querySceneInstService.getOnlyGiftOfferInstByProdInstId(custDto.getCustId(), prodInst.getProdInstId());
            }
            String offerId = Optional.ofNullable(offerInstt).map(KiteOfferInst::getSpecId).orElse("");
            String cateId = Optional.ofNullable(OfferCache.get(offerId)).map(Offer::getCateId).orElse("");
            String prodUseType = Optional.ofNullable(ProductCache.get(prodInst.getProdId())).map(Product::getProdUseType).orElse("");
            if ("2000".equals(prodUseType) || (!KiteStringUtils.equals(prodInst.getProdInstId(), offerInstId) && !GoodsInfoTransfer.isAddRoleOffer(offerId, cateId))) {
                prodInstFuncs.addAll(this.querySceneInstService.listProdInstFuncs(custDto.getCustId(), prodInst.getProdInstId()));
            }
        }
        // 获取删除的功能产品
        List<KiteInstChange> instChangeList = querySceneInstService.listInstChanges(context.getSceneInstId(), InstType.PROD_INST_FUNC);
        for (KiteInstChange instChange : instChangeList) {
            if (KiteStringUtils.isEqual(instChange.getNewValue(), ActionType.D.name())
                && !KiteStringUtils.isEqual(instChange.getOldValue(), ActionType.A.name())) {
                KiteProdInstFunc delProdFuncInst = querySceneInstService.getProdInstFunc(custDto.getCustId(), instChange.getInstId());
                if (Objects.nonNull(delProdFuncInst) && (this.isDependence(custDto.getCustId(), prodInstId, delProdFuncInst.getProdId())
                    || KiteStringUtils.equals(delProdFuncInst.getAccProdInstId(), prodInstId))) {
                    prodInstFuncs.add(delProdFuncInst);
                }
            }
        }
        KiteSceneInst kiteSceneInst = querySceneInstService.getSceneInst(context.getSceneInstId());
        String serviceOfferId = kiteSceneInst.getServiceOfferId();
        //主产品大数据附件类型特殊转换
        dealAttachementsAttrGrp(mainProdInst, kitePosAttrDTOS, context, createDateStr, offerInst.getOfferId(), sceneInstId);
        /*String dcPublic = DcPublicCache.getCodea("20210506001", cateIdAttr.getValue());
        if (KiteStringUtils.isNotEmpty(dcPublic)) {
            List<String> fieldNamesList = Arrays.asList(dcPublic.split(","));
            for (String fieldName : fieldNamesList) {
                KiteAttr kiteAttrOpp =querySceneInstService.getInstAttr(context.getCustId(), mainProdInst.getInstType(), mainProdInst.getProdInstId(), fieldName);
                if(Objects.nonNull(mainProdInst.getAttr(fieldName))&&kiteAttrOpp.getAttrValueTypeId().equals("98F"))dealAttachements(kiteAttrOpp,kitePosAttrDTOS,serviceOfferId);
            }
        }*/
        //互联网大带宽附件属性特殊处理
        if (Objects.nonNull(cateIdAttr) && KiteStringUtils.equals(ProdCateUtil.getSingleCateId(ProdCateUtil.DIA_CODE), cateIdAttr.getValue())) {
            Map<String, Object> attachmentsMap = new HashMap<String, Object>();
            Map<String, Object> originAttachments = querySceneInstService.getExtParameterValue(sceneInstId, "DIA_ORIGIN_ATTACHMENTS");
            // 大带宽附件属性组 受否大带宽 为是
            if (Objects.nonNull(mainProdInst) && Objects.nonNull(mainProdInst.getAttr("2_0000078")) && KiteStringUtils.isEqual(mainProdInst.getAttrValue("2_0000078"), "1_0000106")) {
                KiteAttr kiteAttr = querySceneInstService.getInstAttr(context.getCustId(), mainProdInst.getInstType(), mainProdInst.getProdInstId(), "300000203");
                if (Objects.nonNull(kiteAttr)) {
                    String jsonStr = kiteAttr.getValue();
                    boolean isAdd = true;
                    boolean isDel = true;
                    boolean isKeep = true;
                    if (!KiteStringUtils.isEmpty(jsonStr)) {
                        JSONArray arrs = JSONArray.parseArray(jsonStr);
                        for (int i = 0; i < arrs.size(); i++) {
                            JSONObject obj = arrs.getJSONObject(i);
                            String name = obj.getString("fileName");
                            if (KiteStringUtils.isNotEmpty(obj.getString("type"))) {
                                name = KiteStringUtils.join(obj.getString("fileName"), SymbolConsts.PERIOD, obj.getString("type"));
                            }
                            // 新增的附件动作类型
                            String actionType = obj.getString("actionType");
                            List<KitePosAttrDTO> attachmentsAttrs = new ArrayList<>();
                            //特殊处理带宽附件的 210004325附件类型  210004326附件内容  210004327RUL路径   210004328上传时间 属性
                            String fieldNames = DcPublicCache.getCodea("20210506", "300000203");
                            if (KiteStringUtils.isNotEmpty(fieldNames)) {
                                String changeType = "";
                                List<String> fieldNamesList = Arrays.asList(fieldNames.split(","));
                                for (String fieldName : fieldNamesList) {
                                    KiteAttr attr = mainProdInst.getAttr(fieldName);
                                    if (Objects.nonNull(attr)) {
                                        KitePosAttrDTO posAttachmentsAttr = new KitePosAttrDTO();
                                        posAttachmentsAttr.setCode(fieldName);
                                        posAttachmentsAttr.setType("STRING");
                                        posAttachmentsAttr.setStartDate(createDateStr);
                                        posAttachmentsAttr.setEndDate(LocalKeyConsts.ATTR_SEND_DATE);
                                        //210004325附件类型
                                        if (KiteStringUtils.isEqual(fieldName, "210004325")) {
                                            attr.getAttrValues().stream().forEach(value -> {
                                                if (KiteStringUtils.isEqual(value.getAttrValueName(), obj.getString("fileTypeName"))) {
                                                    posAttachmentsAttr.setValue(value.getAttrValue());
                                                }
                                            });
                                        }
                                        //210004326附件内容
                                        if (KiteStringUtils.isEqual(fieldName, "210004326")) {
                                            posAttachmentsAttr.setValue(name);
                                        }
                                        //210004327RUL路径
                                        String url = obj.getString("attachmentUrl");
                                        if (KiteStringUtils.isEqual(fieldName, "210004327")) {
                                            posAttachmentsAttr.setValue(url);
                                        }
                                        // 210004328上传时间
                                        if (KiteStringUtils.isEqual(fieldName, "210004328")) {
                                            posAttachmentsAttr.setValue(obj.getString("createDate"));
                                        }
                                        if (ActionType.A.name().equals(actionType)) {
                                            changeType = ChangeTypeUtils.CHANGE_TYPE_A;
                                        } else if (ActionType.D.name().equals(actionType)) {
                                            // 删除结束时间取当前时间，开始时间取初值，初值和当前值一致
                                            posAttachmentsAttr.setOriginValue(posAttachmentsAttr.getValue());
                                            posAttachmentsAttr.setEndDate(createDateStr);
                                            posAttachmentsAttr.setStartDate(this.getAttachmentStartDate(url, originAttachments));
                                            changeType = ChangeTypeUtils.CHANGE_TYPE_D;
                                        } else {
                                            changeType = ChangeTypeUtils.CHANGE_TYPE_K;
                                            /**
                                             * 当为环节时，changeType保持为初始值，附件只有新增和删除操作，没有修改操作
                                             * 订单审核  OrderAudit 订单签订 OrderSigned 核查转定 OrderArchive 订单起租 OrderStartRent
                                             * 订单重提 OrderResubmit 业务开通 OrderServiceOpen 订单止租 OrderStopRent
                                             */
/*                                            if (KiteStringUtils.isNotEmpty(nodeCode) && KiteStringUtils.equalsAny(nodeCode, "OrderSigned", "OrderAudit", "OrderResubmit", "OrderStartRent", "OrderArchive", "OrderServiceOpen", "OrderStopRent")) {
                                                changeType = this.getAttachmentOriginChangeType(url, originAttachments);
                                            }*/
                                        }
                                        posAttachmentsAttr.setChangeType(changeType);

                                        attachmentsAttrs.add(posAttachmentsAttr);
                                    }
                                }
                                // 增加changType属性
                                KitePosAttrDTO changeTypeAttr = new KitePosAttrDTO();
                                changeTypeAttr.setCode("changeType");
                                changeTypeAttr.setValue(changeType);
                                changeTypeAttr.setChangeType(changeType);
                                changeTypeAttr.setStartDate(createDateStr);
                                changeTypeAttr.setEndDate(LocalKeyConsts.ATTR_SEND_DATE);
                                if (ActionType.D.name().equals(actionType)) {
                                    changeTypeAttr.setEndDate(createDateStr);
                                }
                                attachmentsAttrs.add(changeTypeAttr);
                                if(!KiteStringUtils.equals(ActionType.A.name(),actionType)){
                                    isAdd = false;
                                }
                                if(!KiteStringUtils.equals(ActionType.D.name(),actionType)){
                                    isDel = false;
                                }
                                if(!KiteStringUtils.equals(ActionType.K.name(),actionType)){
                                    isKeep = false;
                                }
                            }
                            String attrGroupInstId = obj.getString("attrGroupInstId");
                            if(KiteStringUtils.isEmpty(attrGroupInstId)){
                                attrGroupInstId = this.getAttrGroupInstIdFromProdInst(context, prodInstId, "");
                            }
                            attachmentsMap.put(attrGroupInstId, attachmentsAttrs);
                        }
                    }
                    KitePosAttrDTO posAttr = kitePosAttrDTOS.stream().filter(attr -> KiteStringUtils.equals(attr.getCode(), kiteAttr.getFieldName())).findFirst().orElse(null);
                    if (Objects.nonNull(posAttr)) {
                        // 属性组去掉初值
                        posAttr.setOriginValue(null);
                        posAttr.setValue(JSONObject.toJSONString(attachmentsMap));
                        posAttr.setType("ATTR_GROUP");
                        if(KiteMapUtils.isNotEmpty(attachmentsMap)){//根据所有附件的状态更新changeType
                            if(isAdd){
                                posAttr.setChangeType(ChangeTypeUtils.CHANGE_TYPE_A);
                            }else if(isDel){
                                posAttr.setChangeType(ChangeTypeUtils.CHANGE_TYPE_D);
                            }else if(isKeep){
                                posAttr.setChangeType(ChangeTypeUtils.CHANGE_TYPE_K);
                            }else {
                                posAttr.setChangeType(ChangeTypeUtils.CHANGE_TYPE_M);
                            }
                        }
                    }
                }
            }
        }
        Map<String, List<KiteProdInstFunc>> grpProdInstFuncMap = KiteListUtils.groupBy(prodInstFuncs, "specId");
        Map<String, KitePosAttrDTO> attrGroupMap = querySceneInstService.getExtParameterValue(context.getSceneInstId(), "attrGroupMap_".concat(prodInstId));
        Iterator<String> it = grpProdInstFuncMap.keySet().iterator();

        while (it.hasNext()) {
            String specIdd = it.next();
            String specId = DcPublicCache.getPCode(LocalDcPublicConsts.ATTR_CODE, specIdd);
            if (KiteStringUtils.isEmpty(specId)) {
                specId = specIdd;
            }
            KitePosAttrDTO grpAttr = new KitePosAttrDTO();
            Map<String, Object> grpMap = new HashMap<String, Object>();
            grpAttr.setCode(specId);
            grpAttr.setType(LocalKeyConsts.ATTR_TYPE_GROUP);
            List<KiteProdInstFunc> list = grpProdInstFuncMap.get(specIdd);
            if (KiteListUtils.isEmpty(list)) {
                continue;
            }
            String grpStartDate = null;
            String grpEndDate = null;
            if (KiteMapUtils.isNotEmpty(attrGroupMap)) {
                KitePosAttrDTO kitePosAttrDTO = attrGroupMap.get(grpAttr.getCode());
                if (Objects.nonNull(kitePosAttrDTO)) {
                    grpStartDate = kitePosAttrDTO.getStartDate();
                    grpEndDate = kitePosAttrDTO.getEndDate();
                }
            }
            for (KiteProdInstFunc inst : list) {
                //延期不拼装原有的延期信息
                if (KiteStringUtils.isEqual(LocalServiceOfferConsts.SERVICE_OFFER_DELAY, serviceOfferId)) {
                    String zPostponeProdId = DcPublicCache.getCodea("20210326001", "postponeProdId");
                    List<ProdRelInfo> prodRelInfos = ProdRelCache.get(mainProdInst.getProdId());
                    if(KiteListUtils.isNotEmpty(prodRelInfos)){
                        ProdRelInfo prodRelInfo = prodRelInfos.get(0);
                        zPostponeProdId = prodRelInfo.getzProdId();
                    }
                    if (KiteStringUtils.equals(zPostponeProdId, inst.getSpecId()) && ActionType.K.equals(inst.getActionType())) {
                        continue;
                    }
                }
                List<KitePosAttrDTO> attrs = new ArrayList<>();
                Map<String, KiteAttr> attrMap = inst.getAttrMap();
                Iterator<String> ait = attrMap.keySet().iterator();
                while (ait.hasNext()) {
                    String fieldName = ait.next();

                    KiteAttr kiteAttr = attrMap.get(fieldName);
                    // 变更的时候属性值清空，也需要送下去
                    if ((KiteStringUtils.isEmpty(kiteAttr.getValue()) && KiteStringUtils.isEmpty(kiteAttr.getOriginValue()))
                        || (KiteStringUtils.isEqual(LocalServiceOfferConsts.SERVICE_OFFER_DELAY, serviceOfferId)
                        && KiteStringUtils.equals(fieldName, "200002981"))) { // 延期业务不拼装业务号码
                        continue;
                    }
                    KitePosAttrDTO posAttr = genKitePosAttr(kiteAttr, context.getSceneInstId(), inst.getInstType(), inst.getInstId(), context.getCustId(), createDateStr, context.getIsBcmcFlow());
                    if (!KiteObjectUtils.isEmpty(posAttr)) {
                        attrs.add(posAttr);
                    }
                }
                // 资费计划基本信息，设置平台服务基本和平台功能费属性
                Product product = ProductCache.get(specId);
                if (!KiteObjectUtils.isEmpty(product)) {
                    if (KiteStringUtils.equalsAny(product.getProdNbr(), "300000170", "300000152", LocalKeyConsts.FUNC_PROD_ID_YF5GZF_BASE)) {
                        if (!KiteObjectUtils.isEmpty(mainProdInst.getAttr("200003681")) && !KiteStringUtils.isEmpty(mainProdInst.getAttrValue("200003681"))) {
                            KitePosAttrDTO posAttr = genKitePosAttr(mainProdInst.getAttr("200003681"), context.getSceneInstId(), mainProdInst.getInstType(), mainProdInst.getInstId(), context.getCustId(), createDateStr, context.getIsBcmcFlow());
                            if (!KiteObjectUtils.isEmpty(posAttr)) {
                                if (KiteStringUtils.isEqual(inst.getActionType().name(), ActionType.D.name())) {
                                    posAttr.setChangeType(ChangeTypeUtils.CHANGE_TYPE_D);
                                    posAttr.setEndDate(createDateStr);
                                } else if (KiteStringUtils.isEqual(inst.getActionType().name(), ActionType.A.name())) {
                                    posAttr.setChangeType(ChangeTypeUtils.CHANGE_TYPE_A);
                                }
                                attrs.add(posAttr);
                            }
                        }
                        if (!KiteObjectUtils.isEmpty(mainProdInst.getAttr("200004024")) && !KiteStringUtils.isEmpty(mainProdInst.getAttrValue("200004024"))) {
                            KitePosAttrDTO posAttr = genKitePosAttr(mainProdInst.getAttr("200004024"), context.getSceneInstId(), mainProdInst.getInstType(), mainProdInst.getInstId(), context.getCustId(), createDateStr, context.getIsBcmcFlow());
                            if (!KiteObjectUtils.isEmpty(posAttr)) {
                                if (KiteStringUtils.isEqual(inst.getActionType().name(), ActionType.D.name())) {
                                    posAttr.setChangeType(ChangeTypeUtils.CHANGE_TYPE_D);
                                    posAttr.setEndDate(createDateStr);
                                } else if (KiteStringUtils.isEqual(inst.getActionType().name(), ActionType.A.name())) {
                                    posAttr.setChangeType(ChangeTypeUtils.CHANGE_TYPE_A);
                                }
                                attrs.add(posAttr);
                            }
                        }
                    }
                }
                // 5G切片属性组设置是否订购5G切片属性为是
                if (KiteStringUtils.equals("300000159", specId)) {
                    KiteAttr kiteAttr = querySceneInstService.getInstAttr(context.getCustId(), mainProdInst.getInstType(), mainProdInst.getProdInstId(), "200004057");
                    if (Objects.nonNull(kiteAttr)) {
                        KitePosAttrDTO posAttr = genKitePosAttr(kiteAttr, context.getSceneInstId(), mainProdInst.getInstType(), mainProdInst.getProdInstId(), context.getCustId(), createDateStr, context.getIsBcmcFlow());
                        if (!KiteObjectUtils.isEmpty(posAttr)) {
                            if (KiteStringUtils.isEqual(inst.getActionType().name(), ActionType.D.name())) {
                                posAttr.setChangeType(ChangeTypeUtils.CHANGE_TYPE_D);
                                posAttr.setEndDate(createDateStr);
                            } else if (KiteStringUtils.isEqual(inst.getActionType().name(), ActionType.A.name())) {
                                posAttr.setChangeType(ChangeTypeUtils.CHANGE_TYPE_A);
                            }
                            attrs.add(posAttr);
                        }
                    }
                }
                this.addChangeTypeAttr(attrs, inst.getActionType(), createDateStr, grpStartDate, grpEndDate);
                String attrGroupInstId = this.getAttrGroupInstIdFromProdInstFunc(context, inst.getInstId(), specIdd, specId);
                grpMap.put(attrGroupInstId, attrs);
            }
            grpAttr.setChangeType(prodFuncChangeType(list));
            grpAttr.setValue(JSONObject.toJSONString(grpMap));
            grpAttr.setStartDate(grpStartDate);
            grpAttr.setEndDate(grpEndDate);
            grpAttrs.add(grpAttr);
        }
        return grpAttrs;
    }

    /**
     * @param prodInst
     * @param kitePosAttrDTOS
     * @param context
     * @param createDateStr
     * @param offerId
     * @param sceneInstId
     * @return
     */
    private List<KitePosAttrDTO> dealAttachementsAttrGrp(KiteProdInst prodInst, List<KitePosAttrDTO> kitePosAttrDTOS, KitePosHandlerContext context, String createDateStr, String offerId, String sceneInstId) {
        //DcPublic dcPublic = DcPublicCache.get(dcCode, dcKey);//附件字段
        KiteSceneInst kiteSceneInst = querySceneInstService.getSceneInst(context.getSceneInstId());
        if (!Objects.nonNull(prodInst)) {
            return kitePosAttrDTOS;
        }
        KiteAttr groupAttr = prodInst.getAttr("ATTAGRP");
        String groupId = "";
        if (Objects.nonNull(groupAttr)) {
            groupId = groupAttr.getDefaultValue();//获取产品下配置的组id
        }
        if (KiteStringUtils.isEmpty(groupId)) {
            return kitePosAttrDTOS;//没有配置则不用处理
        }
        KiteAttr group = prodInst.getAttr(groupId);//报文中的附件
        List<Map.Entry<String, KiteAttr>> cfCodes = prodInst.getAttrMap().entrySet().stream().filter(en -> KiteStringUtils.equals(en.getValue().getAttrValueTypeId(), "98F")).collect(Collectors.toList());
        Map<String, Object> attachmentsMap = new HashMap<String, Object>();
        boolean isNoChange = true;
        boolean isAdd = true;
        boolean isDel = true;
        //cfCodes需要处理为同一属性组的多个附件属性
        for (Map.Entry<String, KiteAttr> cfEntry : cfCodes) {
            KiteAttr kiteAttr = cfEntry.getValue();
            String kiteAttrvalue = kiteAttr.getValue();
            if(KiteStringUtils.isEmpty(kiteAttrvalue)){ continue; }
            JSONArray ktArrs = JSONArray.parseArray(kiteAttrvalue);
            String fieldNames = DcPublicCache.getCodea("20210506", groupId);//转换的属性组字段
            //一个属性上的多个附件ktArrs
            for(Object obj:ktArrs){
                JSONObject ktObj = JSONObject.parseObject(JSON.toJSONString(obj));
                String name = ktObj.getString("fileName");
                if (KiteStringUtils.isNotEmpty(ktObj.getString("type"))) {
                    name = KiteStringUtils.join(ktObj.getString("fileName"), SymbolConsts.PERIOD, ktObj.getString("type"));
                }
                List<String> fieldNamesList = Arrays.asList(fieldNames.split(","));
                List<KitePosAttrDTO> attachmentsAttrs = new ArrayList<>();//一个附件一个属性列表
                String actionType = ktObj.getString("actionType");
                String changeType = "";
                //fieldNamesList -- 属性组包含的属性 处理
                for (String fieldName : fieldNamesList) {
                    KitePosAttrDTO posAttachmentsAttr = new KitePosAttrDTO();
                    posAttachmentsAttr.setCode(fieldName);
                    posAttachmentsAttr.setType("STRING");
                    posAttachmentsAttr.setStartDate(createDateStr);
                    posAttachmentsAttr.setEndDate(LocalKeyConsts.ATTR_SEND_DATE);
                    //210004325附件类型
                    switch (fieldName) {
                        case "210004325":
                            KiteAttr attr = prodInst.getAttr(fieldName);
                            List<KiteAttrValue> attrList = attr.getAttrValues();
                            attrList = attrList.stream().filter(it -> KiteStringUtils.isNotEmpty(it.getAttrValue())).collect(Collectors.toList());
                            if (attrList.size() == 1) {//如果只有一个文件类型 则默认使用该文件类型
                                posAttachmentsAttr.setValue(attrList.get(0).getAttrValue());
                                break;
                            } else {
                               // if (cfCodes.size() > 1) {//多个字段判断是否有类型字段映射
                                    List<DcPublic> dcTypes = DcPublicCache.getByPcode("20210506002", offerId, cfEntry.getKey());
                                    if (KiteListUtils.isNotEmpty(dcTypes)) {
                                        posAttachmentsAttr.setValue(dcTypes.get(0).getCodea());
                                        break;
                                    }
                                //}
                            }
                            attrList.stream().forEach(value -> {
                                if (KiteStringUtils.isEqual(value.getAttrValueName(), ktObj.getString("fileTypeName"))) {
                                    posAttachmentsAttr.setValue(value.getAttrValue());
                                }
                            });
                            break;
                        case "210004326":
                            posAttachmentsAttr.setValue(name);
                            break;
                        case "210004327":
                            posAttachmentsAttr.setValue(ktObj.getString("attachmentUrl"));
                            break;
                        case "210004328":
                            posAttachmentsAttr.setValue(ktObj.getString("createDate"));
                            break;
                        default:break;
                    }
                    Map<String, Object> originAttachments = querySceneInstService.getExtParameterValue(sceneInstId + "_" + offerId , "DIA_ORIGIN_ATTACHMENTS");
                    //根据附件状态处理changeType
                    if (ActionType.A.name().equals(actionType)) {
                        changeType = ChangeTypeUtils.CHANGE_TYPE_A;
                    } else if (ActionType.D.name().equals(actionType)) {
                        // 删除结束时间取当前时间，开始时间取初值，初值和当前值一致
                        posAttachmentsAttr.setOriginValue(posAttachmentsAttr.getValue());
                        posAttachmentsAttr.setEndDate(createDateStr);
                        posAttachmentsAttr.setStartDate(this.getAttachmentStartDate(ktObj.getString("attachmentUrl"), originAttachments));
                        changeType = ChangeTypeUtils.CHANGE_TYPE_D;
                    } else {
                        changeType = ChangeTypeUtils.CHANGE_TYPE_K;
/*                        String nodeCode = querySceneInstService.getExtParameterValue(sceneInstId, "nodeCode");
                        if (KiteStringUtils.isNotEmpty(nodeCode) && KiteStringUtils.equalsAny(nodeCode, "OrderSigned", "OrderAudit", "OrderResubmit", "OrderStartRent", "OrderArchive", "OrderServiceOpen", "OrderStopRent")) {
                            changeType = this.getAttachmentOriginChangeType(ktObj.getString("attachmentUrl"), originAttachments);
                        }*/
                    }
                    posAttachmentsAttr.setChangeType(changeType);
                    attachmentsAttrs.add(posAttachmentsAttr);
                }
                // 增加changType属性
                KitePosAttrDTO changeTypeAttr = new KitePosAttrDTO();
                changeTypeAttr.setCode("changeType");
                changeTypeAttr.setValue(changeType);
                changeTypeAttr.setChangeType(changeType);
                changeTypeAttr.setStartDate(createDateStr);
                changeTypeAttr.setEndDate(LocalKeyConsts.ATTR_SEND_DATE);
                attachmentsAttrs.add(changeTypeAttr);
                //取原始实例Id取不到  重新获取
                String attrGroupInstId = ktObj.getString("attrGroupInstId");
                if(KiteStringUtils.isEmpty(attrGroupInstId)){
                    attrGroupInstId = this.getAttrGroupInstIdFromProdInst(context, prodInst.getProdInstId(), "");
                }
                attachmentsMap.put(attrGroupInstId, attachmentsAttrs);
                if(!KiteStringUtils.equals(changeType,ChangeTypeUtils.CHANGE_TYPE_A)){
                    isAdd = false;
                }
                if(!KiteStringUtils.equals(changeType,ChangeTypeUtils.CHANGE_TYPE_D)){
                    isDel = false;
                }
                if(KiteStringUtils.equalsAny(changeType,ChangeTypeUtils.CHANGE_TYPE_D,ChangeTypeUtils.CHANGE_TYPE_A,ChangeTypeUtils.CHANGE_TYPE_M)){
                    isNoChange = false;
                }
            }
            if (KiteStringUtils.isNotEmpty(sceneInstId)) {
                kiteAttr.setShowType("E");
                operateSceneInstService.setAttr(sceneInstId, prodInst.getInstType(), prodInst.getProdInstId(), kiteAttr);
            }

            Iterator<KitePosAttrDTO> iterator = kitePosAttrDTOS.iterator();
            while (iterator.hasNext()) {
                KitePosAttrDTO it = iterator.next();
                if (KiteStringUtils.equals(it.getCode(), kiteAttr.getFieldName())) {
                    iterator.remove();
                }
            }
        }
        KitePosAttrDTO posAttr = kitePosAttrDTOS.stream().filter(attr -> KiteStringUtils.equals(attr.getCode(), group.getFieldName())).findFirst().orElse(null);
        if (Objects.nonNull(posAttr)) {
            // 属性组去掉初值
            posAttr.setOriginValue(null);
            String value = JSONObject.toJSONString(attachmentsMap);
            posAttr.setValue(value);
            if(!KiteStringUtils.equals("2826",kiteSceneInst.getServiceOfferId())||isAdd){
                posAttr.setChangeType(ChangeTypeUtils.CHANGE_TYPE_A);
            }else if(isDel){
                posAttr.setChangeType(ChangeTypeUtils.CHANGE_TYPE_D);
            }else if(!isNoChange){
                posAttr.setChangeType(ChangeTypeUtils.CHANGE_TYPE_M);
            }else if(isNoChange){
                posAttr.setChangeType(ChangeTypeUtils.CHANGE_TYPE_K);
            }
            posAttr.setType("ATTR_GROUP");
        }

        return kitePosAttrDTOS;
    }

    //特殊流程 处理大数据的附件和备注
    //封装附件
    private String dealAttachements(KiteAttr kiteAttr, List<KitePosAttrDTO> kitePosAttrDTOS, String serviceOfferId) {
        String kiteAttrvalue = kiteAttr.getValue();
        Map attachementsMap = new HashMap();
        if (!KiteStringUtils.equals(kiteAttrvalue, "[]")) {
            List attachments = new ArrayList<>();
            if (!KiteStringUtils.isEmpty(kiteAttrvalue)) {
                //变更处理serviceOfferId
                if (kiteAttrvalue.contains("orderAttachArr") && "2826".equals(serviceOfferId)) {
                    JSONObject jsonObject = JSONObject.parseObject(kiteAttrvalue);
                    kiteAttrvalue = JSON.toJSONString(jsonObject.get("orderAttachArr"));
                } else if ((kiteAttrvalue.contains("orderAttachArr"))) {
                    return null;
                }
                JSONArray arrs = JSONArray.parseArray(kiteAttrvalue);
                for (int i = 0; i < arrs.size(); i++) {
                    JSONObject obj = arrs.getJSONObject(i);
                    /*        attachementsMap.put("ATTACHMENTS_TYPE",obj.getString("fileType").replace("ATTACHMENTS_TYPE_", ""));*/
                    attachementsMap.put("fileName", obj.getString("attachmentUrl"));
                    attachementsMap.put("showSize", "");
                    attachementsMap.put("backFileName", obj.getString("fileTypeName"));
                    String name = obj.getString("fileName");
                    if (KiteStringUtils.isNotEmpty(obj.getString("type"))) {
                        name = KiteStringUtils.join(obj.getString("fileName"), SymbolConsts.PERIOD, obj.getString("type"));
                    }
                    attachementsMap.put("backFileName", name);
                    // 文件类型图标:icon- fileType,
                    attachementsMap.put("fileTypeIcon", obj.getString("fileTypeIcon"));
                    attachementsMap.put("uploadTime", obj.getString("createDate"));
                    attachementsMap.put("fileType", obj.getString("type"));
                    attachments.add(attachementsMap);
                    break;
                }
            }
            if (!KiteObjectUtils.isEmpty(attachments)) {
                Map dataMap = new HashMap<>();
                dataMap.put("orderAttachArr", attachments);
                JSONObject.toJSONString(dataMap);
                KitePosAttrDTO posAttr = kitePosAttrDTOS.stream().filter(attr -> KiteStringUtils.equals(attr.getCode(), kiteAttr.getFieldName())).findFirst().orElse(null);
                posAttr.setValue(JSONObject.toJSONString(dataMap).toString());
                return dataMap.toString();
            }
        }
        return null;
    }

    /**
     * 属性组实例变动属性
     *
     * @param attrs
     * @param actionType
     * @param createDateStr 受理时间
     * @param startDate
     * @param endDate
     */
    private void addChangeTypeAttr(List<KitePosAttrDTO> attrs, ActionType actionType, String createDateStr, String startDate, String endDate) {
        KitePosAttrDTO chgTypeAttr = new KitePosAttrDTO();
        chgTypeAttr.setCode("changeType");
        chgTypeAttr.setValue(ChangeTypeUtils.getChangeType(actionType.name()));
        chgTypeAttr.setStartDate(Optional.ofNullable(startDate).orElse(createDateStr));
        String endDateStr = KiteStringUtils.equals(actionType.name(), ActionType.D.name()) ?
            createDateStr : Optional.ofNullable(endDate).orElse(LocalKeyConsts.ATTR_SEND_DATE);
        chgTypeAttr.setEndDate(endDateStr);
        chgTypeAttr.setChangeType(ChangeTypeUtils.getChangeType(actionType.name()));
        attrs.add(chgTypeAttr);
    }

    private String prodFuncChangeType(List<KiteProdInstFunc> instFuncs) {
        if (KiteListUtils.isEmpty(instFuncs)) {
            return ChangeTypeUtils.getChangeType(ActionType.K.name());
        }
        int noChangeNum = 0;
        int addChangeNum = 0;
        int delChangeNum = 0;
        for (KiteProdInstFunc prodFunc : instFuncs) {
            if (KiteStringUtils.isEqual(ActionType.K.name(), prodFunc.getActionType().name())) {
                noChangeNum = noChangeNum + 1;
                continue;
            }
            if (KiteStringUtils.isEqual(ActionType.A.name(), prodFunc.getActionType().name())) {
                addChangeNum = addChangeNum + 1;
                continue;
            }
            if (KiteStringUtils.isEqual(ActionType.D.name(), prodFunc.getActionType().name())) {
                delChangeNum = delChangeNum + 1;
                continue;
            }
        }
        if (noChangeNum == instFuncs.size()) {
            return ChangeTypeUtils.getChangeType(ActionType.K.name());
        }
        if (addChangeNum == instFuncs.size()) {
            return ChangeTypeUtils.getChangeType(ActionType.A.name());
        }
        if (delChangeNum == instFuncs.size()) {
            return ChangeTypeUtils.getChangeType(ActionType.D.name());
        }
        return ChangeTypeUtils.getChangeType(ActionType.M.name());
    }

    @SuppressWarnings("unchecked")
    private void packagePayRelation(KitePosHandlerContext context, KitePosGoodsDTO goods) {
        List<KitePosGoodsPayRealtionDTO> payRelations = new ArrayList<>();
        IQuerySceneInstService querySceneInstService = SpringUtil.getBean(IQuerySceneInstService.class);
        Date createDate = querySceneInstService.getSceneInst(context.getSceneInstId()).getCreateDate();
        String createDateStr = KiteDateUtils.formatDate(createDate, KiteDateUtils.DATE_TIME_FORMAT_14);
        KiteSceneInst kiteSceneInst = querySceneInstService.getSceneInst(context.getSceneInstId());
        //传输计划变更时，payRelation有数据不需要重新封装
        if (!KiteListUtils.isEmpty(goods.getPayRelation())) {
            return;
        }
        if (KiteStringUtils.equalsAny(kiteSceneInst.getServiceOfferId(), LocalServiceOfferConsts.SERVICE_OFFER_COLLECTION_GROUP_ADD, LocalServiceOfferConsts.SERVICE_OFFER_COLLECTION_GROUP_DEL)) {
            goods.setPayRelation(payRelations);
            return;
        }

        List<KiteInstChange> instChangeList = querySceneInstService.listInstChanges(context.getSceneInstId(), InstType.OFFER_INST_ACCT);
        for (KiteInstChange instChange : instChangeList) {
            if (KiteStringUtils.isEqual(instChange.getInstId(), goods.getInstanceId())
                && KiteStringUtils.isEqual(instChange.getNewValue(), ActionType.D.name())
                && !KiteStringUtils.isEqual(instChange.getOldValue(), ActionType.A.name())) {

                List<KiteOfferInstAcct> delOfferInstAccts = querySceneInstService.listInsts(context.getSceneInstId(), Collections.singletonList(InstType.OFFER_INST_ACCT));
                // 删除的付费关系
                delOfferInstAccts.forEach((acctRel) -> {
                    if (KiteStringUtils.isEqual(ActionType.D.name(), acctRel.getActionType().name())
                        && KiteStringUtils.isEqual(instChange.getSubInstId(), acctRel.getInstId())) {
                        KitePosGoodsPayRealtionDTO payRelation = new KitePosGoodsPayRealtionDTO();

                        payRelation.setInstanceId(acctRel.getInstId());
                        payRelation.setStartDate(KiteStringUtils.isEmpty(acctRel.getStartDate()) ?
                            createDateStr :
                            KiteDateUtils
                                .getCurrentDayOfMonth(acctRel.getStartDate().split("-")[0], acctRel.getStartDate().split("-")[1]));
                        payRelation.setEndDate(KiteStringUtils.isEmpty(acctRel.getEndDate()) ?
                            LocalKeyConsts.ATTR_SEND_DATE :
                            KiteDateUtils
                                .getLastDayOfMonth(acctRel.getEndDate().split("-")[0], acctRel.getEndDate().split("-")[1]));
                        payRelation.setPayWay(acctRel.getPayWay()); //0全额
                        payRelation.setPayLimit(acctRel.getPayLimit()); //
                        payRelation.setPayitemCode(acctRel.getAcctItemId()); //0全额
                        payRelation.setIsDefault(Integer.valueOf(Optional.ofNullable(acctRel.getIsDefault()).orElse("0"))); //默认
                        payRelation.setEndDate(createDateStr);
                        payRelation.setAccountInstId(getAccountInstId(context, acctRel.getAcctId(), acctRel.getActionType().name()));
                        payRelation.setFeeCycle(this.querySceneInstService.getCommonAttrValue(context.getSceneInstId(), "ORD10233"));
                        payRelation.setAccountCycle(this.querySceneInstService.getCommonAttrValue(context.getSceneInstId(), "ORD10234"));
                        payRelation.setChangeType(ChangeTypeUtils.getChangeType(acctRel.getActionType().name()));
                        if (CuccPosServiceUtils.isRouteUser(context.getSceneInstId(), context.getCustId())) {
                            payRelation.setDestItemId(acctRel.getExtInstId());
                        }
                        payRelations.add(payRelation);

                    }

                });
            }
        }

        List<KiteOfferInstAcct> offerInstAcctRels = querySceneInstService.listOfferInstAccts(context.getCustId(), goods.getInstanceId());
        if (KiteListUtils.isEmpty(offerInstAcctRels)) {
            String custId = querySceneInstService.getSceneInst(context.getSceneInstId()).getCustId();
            offerInstAcctRels = querySceneInstService
                .listOfferInstAccts(custId, goods.getInstanceId());
        }
        if (Objects.isNull(offerInstAcctRels)) {
            offerInstAcctRels = new ArrayList<>();
        }
        // 新增的付费关系
        offerInstAcctRels.forEach((acctRel) -> {
            KiteInstChange kiteInstChange = instChangeList.stream()
                .filter(change -> acctRel.getInstId().equals(change.getSubInstId()))
                .findFirst().orElse(null);
            ActionType actionType = Objects.nonNull(kiteInstChange) ? kiteInstChange.getActionType() : acctRel.getActionType();
            KitePosGoodsPayRealtionDTO payRelation = new KitePosGoodsPayRealtionDTO();

            String instanceId = IdUtils.generateInstId(InstType.PROD_INST_ACCT);
            payRelation.setInstanceId(instanceId);
            payRelation.setStartDate(KiteStringUtils.isEmpty(acctRel.getStartDate()) ?
                createDateStr :
                KiteDateUtils
                    .getCurrentDayOfMonth(acctRel.getStartDate().split("-")[0], acctRel.getStartDate().split("-")[1]));
            payRelation.setEndDate(KiteStringUtils.isEmpty(acctRel.getEndDate()) ?
                LocalKeyConsts.ATTR_SEND_DATE :
                KiteDateUtils
                    .getLastDayOfMonth(acctRel.getEndDate().split("-")[0], acctRel.getEndDate().split("-")[1]));
            payRelation.setPayWay(acctRel.getPayWay()); //0全额
            payRelation.setPayLimit(acctRel.getPayLimit()); //
            payRelation.setPayitemCode(acctRel.getAcctItemId()); //0全额
            payRelation.setIsDefault(Integer.valueOf(Optional.ofNullable(acctRel.getIsDefault()).orElse("0"))); //默认
            //payRelation.setAccountCycle(acctRel.getAccountCycle());
            //payRelation.setFeeCycle(acctRel.getFeeCycle());
            if (CuccPosServiceUtils.isRouteUser(context.getSceneInstId(), context.getCustId())) {
                payRelation.setDestItemId(acctRel.getExtInstId());
            }
            payRelation.setAccountInstId(getAccountInstId(context, acctRel.getAcctId(), acctRel.getActionType().name()));
            setCommonUserValue(payRelation, context.getSceneInstId());
            payRelation.setChangeType(ChangeTypeUtils.getChangeType(actionType.name()));
            if (KiteStringUtils.isEqual(ActionType.M.name(), actionType.name())) {
                payRelation.setChangeType("9");
            }
            if (isPayRelation(payRelations, payRelation)) {
                payRelations.add(payRelation);
            }
        });
        dealPayRelationAccountingPeriod(context, payRelations);
        // 过户特殊处理
        List<KitePosGoodsPayRealtionDTO> dealAcctTransferDtos = dealPayRelationAccountingTransfer(context, payRelations);
        String isDefaultAcct = querySceneInstService.getCommonAttrValue(context.getSceneInstId(), "isDefaultAcct");
        if (KiteListUtils.isNotEmpty(dealAcctTransferDtos) && KiteStringUtils.equals(ServiceOfferConsts.SERVICE_OFFER_TRANSFER, kiteSceneInst.getServiceOfferId())
            && KiteStringUtils.equals("1", isDefaultAcct)) {
            payRelations.removeIf(account -> !account.getInstanceId().equals(dealAcctTransferDtos.get(0).getInstanceId()));
        }
        goods.setPayRelation(payRelations);
    }

    private boolean isPayRelation(List<KitePosGoodsPayRealtionDTO> payRelations, KitePosGoodsPayRealtionDTO delPayRelation) {
        String accountInstId = delPayRelation.getAccountInstId();
        Integer iSdefault = delPayRelation.getIsDefault();
        for (KitePosGoodsPayRealtionDTO payRelation : payRelations) {
            if (KiteStringUtils.isEqual(payRelation.getAccountInstId(), accountInstId)
                && KiteObjectUtils.nullSafeEquals(payRelation.getIsDefault(), iSdefault)) {
                payRelation.setChangeType(ChangeTypeUtils.CHANGE_TYPE_K);
                return false;
            }
        }
        return true;
    }

    private List<KitePosAttrDTO> packageGoodsAttrInfo(KitePosHandlerContext context, KiteOfferInst offerInst) {
        Map<String, KiteAttr> offerAttrMap = offerInst.getAttrMap();
        List<KitePosAttrDTO> attrs = new ArrayList<>();
        if (Objects.isNull(offerAttrMap) || offerAttrMap.isEmpty()) {
            return attrs;
        }
        IQuerySceneInstService querySceneInstService = SpringUtil.getBean(IQuerySceneInstService.class);
        Date createDate = querySceneInstService.getSceneInst(context.getSceneInstId()).getCreateDate();
        String createDateStr = KiteDateUtils.formatDate(createDate, KiteDateUtils.DATE_TIME_FORMAT_14);

        Iterator<KiteAttr> iterator = offerAttrMap.values().iterator();
        while (iterator.hasNext()) {
            KiteAttr kiteAttr = iterator.next();
            //如果是隐藏属性为H且没有值的 或者 订单信息属性为O的，就不放到报文中。隐藏属性只在极简端有效，例如isnull，price这些。订单属性已在order节点下了
            if (KiteStringUtils.equals(kiteAttr.getShowType(), KeyConsts.PROD_ATTR_SHOW_TYPE_E) || kiteAttr
                .getShowType().equals(LocalKeyConsts.PROD_ATTR_SHOW_TYPE_O) || (
                kiteAttr.getShowType().equals(LocalKeyConsts.KITE_ATTR_CONFIG_SHOW_TYPE_H) && StringUtil
                    .isEmpty(kiteAttr.getValue()))) {
                continue;
            }

            KitePosAttrDTO attr = new KitePosAttrDTO();
            attr.setCode(kiteAttr.getFieldName());
            attr.setType("STRING");
            attr.setStartDate(createDateStr);
            attr.setEndDate(LocalKeyConsts.ATTR_SEND_DATE);
            attr.setValue(getAttrValue(kiteAttr));
            attr.setOriginValue(kiteAttr.getOriginValue());
            if (context.getIsBcmcFlow()) {
                attr.setCname(kiteAttr.getCname());
            }
            attrs.add(attr);
        }

        return attrs;
    }

    private String getAccountInstId(KitePosHandlerContext context, String acctId, String actionType) {
        if (KiteListUtils.isEmpty(context.getPosDto().getAccounts())) {
            return "";
        }
        List<KitePosAccountDTO> accounts;
        accounts = context.getPosDto().getAccounts().stream().filter((acct) -> acctId.equals(acct.getAccountId()))
                .collect(Collectors.toList());
        if (KiteListUtils.isEmpty(accounts)) {
            return "";
        }
        return accounts.get(0).getInstanceId();
    }

    private String getAttrValue(KiteAttr kiteAttr) {
        return KiteStringUtils.isEmpty(kiteAttr.getValue()) ?
            (KiteStringUtils.isEmpty(kiteAttr.getDefaultValue()) ? "" : kiteAttr.getDefaultValue()) :
            kiteAttr.getValue();
    }

    private String getInstanceId(String sceneInstId, String seqNumber, CuccContextCustDTO custDTO) {
        Map<String, String> inParam = new HashMap<>();
        inParam.put("SEQ_TYPE", seqNumber);
        inParam.put("SYS_TYPE", "1");
        inParam.put("SYS_SOURCE", "");
        return LocalQuerySeqHelper.getSeqBySeqType(inParam, sceneInstId, custDTO);
    }

    // 付费关系变更时的处理
    private void dealPayRelationAccountingPeriod(KitePosHandlerContext context, List<KitePosGoodsPayRealtionDTO> payRelations) {
        KitePosOrderDTO order = context.getPosDto().getOrder();
        String serviceOfferId = order.getBizType();
        if (KiteStringUtils.equalsAny(serviceOfferId, ServiceOfferConsts.SERVICE_OFFER_ORDER,
            LocalServiceOfferConsts.SERVICE_OFFER_ORDER, LocalServiceOfferConsts.SERVICE_OFFER_ADD_ORDER,LocalServiceOfferConsts.SERVICE_OFFER_ORDER_OPPER)) {
            return;
        }
        if (KiteListUtils.isEmpty(payRelations)) {
            return;
        }
        String currentDate = DateFormatUtils.getFormatedDate();
        // 新增的默认付费关系
        List<KitePosGoodsPayRealtionDTO> addDefaultPayRelation = payRelations.stream().filter(payRelation -> payRelation.getIsDefault() == 1 && KiteStringUtils.equals(payRelation.getChangeType(), ChangeTypeUtils.CHANGE_TYPE_A)).collect(Collectors.toList());
        // 删除默认付费关系
        List<KitePosGoodsPayRealtionDTO> delDefaultPayRelation = payRelations.stream().filter(payRelation -> payRelation.getIsDefault() == 1 && KiteStringUtils.equals(payRelation.getChangeType(), ChangeTypeUtils.CHANGE_TYPE_D)).collect(Collectors.toList());
        // 新增非默认付费关系
        List<KitePosGoodsPayRealtionDTO> addPayRelation = payRelations.stream().filter(payRelation -> payRelation.getIsDefault() != 1 && KiteStringUtils.equals(payRelation.getChangeType(), ChangeTypeUtils.CHANGE_TYPE_A)).collect(Collectors.toList());
        // 删除非默认付费关系
        List<KitePosGoodsPayRealtionDTO> delPayRelation = payRelations.stream().filter(payRelation -> payRelation.getIsDefault() != 1 && KiteStringUtils.equals(payRelation.getChangeType(), ChangeTypeUtils.CHANGE_TYPE_D)).collect(Collectors.toList());
        // 是否过默认账户，0是不过默认账户
        String isDefaultAcct = querySceneInstService.getCommonAttrValue(context.getSceneInstId(), "isDefaultAcct");
        // 新增默认付费关系，生效账期为下账期
        addDefaultPayRelation.forEach(payRelation -> {
            if (KiteStringUtils.isEqual(isDefaultAcct, "0")) {
                payRelation.setStartDate(DateFormatUtils.getFirstDayInMonth(currentDate, DateFormatUtils.DATE_FORMAT_8));
            } else {
                payRelation.setStartDate(DateFormatUtils.getFirstDayInNextMonth(currentDate, DateFormatUtils.DATE_FORMAT_8));
            }

        });
        // 删除默认付费关系，失效账期是当前账期
        // 删除未生效的默认付费关系，修改act_tag=1
        delDefaultPayRelation.forEach(payRelation -> {
            String startDate = payRelation.getStartDate();
            if (startDate.length() > 5 && KiteListUtils.isNotEmpty(addDefaultPayRelation)) {
                int startDateInt = Integer.parseInt(startDate.substring(0, 6));
                int currentDateInt = Integer.parseInt(DateFormatUtils.formatDate(DateFormatUtils.DATE_TIME_FORMAT_14).substring(0, 6));
                if (startDateInt > currentDateInt) {
                    payRelation.setActTag("1");
                } else {
                    if (KiteStringUtils.isEqual(isDefaultAcct, "0")) {
                        payRelation.setEndDate(DateFormatUtils.getUpDayLastSecInMonth(currentDate, DateFormatUtils.DATE_FORMAT_8));
                        payRelation.setChangeType(ChangeTypeUtils.CHANGE_TYPE_M);
                    } else {
                        payRelation.setEndDate(DateFormatUtils.getLastDayInMonth(currentDate, DateFormatUtils.DATE_FORMAT_8));
                    }
                }
            } else {
                if (KiteStringUtils.isEqual(isDefaultAcct, "0")) {
                    payRelation.setEndDate(DateFormatUtils.getUpDayLastSecInMonth(currentDate, DateFormatUtils.DATE_FORMAT_8));
                    payRelation.setChangeType(ChangeTypeUtils.CHANGE_TYPE_M);
                } else {
                    payRelation.setEndDate(DateFormatUtils.getLastDayInMonth(currentDate, DateFormatUtils.DATE_FORMAT_8));
                }

            }
        });

        // 删除非默认付费关系、截止账期为本账期
        delPayRelation.forEach(payRelation -> {
            payRelation.setEndDate(DateFormatUtils.getLastDayInMonth(currentDate, DateFormatUtils.DATE_FORMAT_8));
        });
    }

    private void setCommonUserValue(KitePosGoodsPayRealtionDTO payRelation, String sceneInstId) {
        // kite_template_module_rel没有集团用户信息模块，实例数据中会没有用户信息，此时取原有的
        List<KitePosUserDTO> users = (List<KitePosUserDTO>) querySceneInstService
            .getExtParameterValue(sceneInstId, "serialNumber");
        String feeCycle = this.querySceneInstService.getCommonAttrValue(sceneInstId, "ORD10233");
        if (KiteStringUtils.isEmpty(feeCycle)) {
            feeCycle = KiteListUtils.isNotEmpty(users) ? users.get(0).getFeeCycle() : "";
        }
        payRelation.setFeeCycle(feeCycle);
        String accountCycle = this.querySceneInstService.getCommonAttrValue(sceneInstId, "ORD10234");
        if (KiteStringUtils.isEmpty(accountCycle)) {
            accountCycle = KiteListUtils.isNotEmpty(users) ? users.get(0).getAccountCycle() : "";
        }
        payRelation.setAccountCycle(accountCycle);
    }

    // 过户 有两条及以上账户关系时特殊处理
    private List<KitePosGoodsPayRealtionDTO> dealPayRelationAccountingTransfer(KitePosHandlerContext context, List<KitePosGoodsPayRealtionDTO> payRelations) {
        IQuerySceneInstService querySceneInstService = SpringUtil.getBean(IQuerySceneInstService.class);
        KiteSceneInst kiteSceneInst = querySceneInstService.getSceneInst(context.getSceneInstId());
        // 只处理过户
        if (!KiteStringUtils.equals(ServiceOfferConsts.SERVICE_OFFER_TRANSFER, kiteSceneInst.getServiceOfferId())) {
            return payRelations;
        }
        if (KiteListUtils.isEmpty(payRelations)) {
            return payRelations;
        }
        String isDefaultAcct = querySceneInstService.getCommonAttrValue(context.getSceneInstId(), "isDefaultAcct");
        if (KiteStringUtils.equals("1", isDefaultAcct) && payRelations.size() > 1) {
            // 只处理有默认付费关系的数据
            payRelations = payRelations.stream().filter(payRelation ->
                payRelation.getIsDefault() == 1
                    && ChangeTypeUtils.CHANGE_TYPE_K.equals(payRelation.getChangeType())
            ).collect(Collectors.toList());
            List<KitePosGoodsPayRealtionDTO> tmpOfferInstAcctRels = new ArrayList<>();
            for (KitePosGoodsPayRealtionDTO payRelation : payRelations) {
                // 获取当前付费关系的起始账期
                String subStartDate = payRelation.getStartDate().substring(0, 6);
                // 获取当前年月
                Calendar cal = Calendar.getInstance();
                cal.add(Calendar.MONTH, 1);
                SimpleDateFormat dft = new SimpleDateFormat("yyyyMM");
                String nextMonth = dft.format(cal.getTime());
                // 只过次月生效的默认账户
                if (KiteStringUtils.equals(subStartDate, nextMonth) && payRelation.getIsDefault() == 1) {
                    // 存在多条次月生效的默认账户或多条默认账户 只取一条账户传下去
                    tmpOfferInstAcctRels.add(payRelation);
                    break;
                }
            }
            if (KiteListUtils.isNotEmpty(tmpOfferInstAcctRels)) {
                return tmpOfferInstAcctRels;
            }
        }
        // 不过默认账户 重提时老账户changeType会变为9，传给下游不会把老账户失效，改为2传给下游
        List<KiteOfferInstAcct> offerInstAcctRels = querySceneInstService.listInsts(context.getSceneInstId(), Collections.singletonList(InstType.OFFER_INST_ACCT));
        if (KiteStringUtils.equals("0", isDefaultAcct) && KiteListUtils.isNotEmpty(offerInstAcctRels)) {
            payRelations.forEach(payRelation -> {
                offerInstAcctRels.forEach(offerInstAcctRel -> {
                    if (ActionType.M.equals(offerInstAcctRel.getOriginalActionType()) && payRelation.getAccountInstId().substring(2).equals(offerInstAcctRel.getInstId())) {
                        payRelation.setChangeType(ChangeTypeUtils.CHANGE_TYPE_M);
                    }
                });
            });
        }
        return payRelations;
    }

    /**
     * 从互联网初始值中获取到startDate，取url节点的即可
     * @param attachmentUrl
     * @param originAttachments
     * @return
     */
    private String getAttachmentStartDate(String attachmentUrl, Map<String, Object> originAttachments) {
        String startDate = "";
        if (Objects.isNull(originAttachments)) {
            return startDate;
        }
        Iterator<String> iterator = originAttachments.keySet().iterator();
        while (iterator.hasNext()) {
            String attrGroupInstId = iterator.next();
            List<KitePosAttrDTO> attrs = KiteMapUtils.getValue(originAttachments, attrGroupInstId);
            KitePosAttrDTO startDateAttr = attrs.stream().filter(attr -> (KiteStringUtils.equals(attr.getCode(), "210004327") && KiteStringUtils.equals(attr.getValue(), attachmentUrl))).findFirst().orElse(null);
            if (Objects.nonNull(startDateAttr)) {
                startDate = startDateAttr.getStartDate();
                break;
            }
        }
        return startDate;
    }

    private String getAttachmentOriginChangeType(String attachmentUrl, Map<String, Object> originAttachments) {
        String originChangeType = "";
        if (Objects.isNull(originAttachments)) {
            return originChangeType;
        }
        Iterator<String> iterator = originAttachments.keySet().iterator();
        while (iterator.hasNext()) {
            String attrGroupInstId = iterator.next();
            List<KitePosAttrDTO> attrs = KiteMapUtils.getValue(originAttachments, attrGroupInstId);
            KitePosAttrDTO changeTypeAttr = attrs.stream().filter(attr -> (KiteStringUtils.equals(attr.getCode(), "210004327") && KiteStringUtils.equals(attr.getValue(), attachmentUrl))).findFirst().orElse(null);
            if (Objects.nonNull(changeTypeAttr)) {
                originChangeType = changeTypeAttr.getChangeType();
                break;
            }
        }
        return originChangeType;
    }

    // 重新计算资费产品的产品编码，包编码以及服务编码
    private void RecalculateFeeAttrs(KiteOfferInst offerInst, KitePosGoodsFeeDTO fee) {
        List<KitePosAttrDTO> attrs = fee.getAttrs().stream().filter(kiteAttr -> KiteStringUtils.equalsAny(kiteAttr.getCode(), "200000106", "200000175", "200000185")).collect(Collectors.toList());
        if (KiteListUtils.isEmpty(attrs)) {
            return;
        }

        Offer offer =OfferCache.get(offerInst.getOfferId());
        Map<String, Object> offerMap = offer.getOfferMap();
        if (KiteMapUtils.isEmpty(offerMap)) {
            return;
        }
        Map<String, Object> feeSpec = new HashMap<>();
        List<Map<String, Object>> productCategroyList = (List) KiteMapUtils.getObject(offerMap, "productCategroy");
        for (Map<String, Object> productCategroy : productCategroyList) {
            if (!KiteStringUtils.isEqual("pay", KiteMapUtils.getString(productCategroy, "productType"))) {
                continue;
            }
            List<Map<String, Object>> feeSpecList = (List) KiteMapUtils.getObject(productCategroy, "products");
            feeSpec = feeSpecList.stream().filter(tempFeeSpec -> KiteStringUtils.isEqual(fee.getCode(), KiteMapUtils.getString(tempFeeSpec, "productCode"))).findFirst().orElse(null);
            if (KiteMapUtils.isNotEmpty(feeSpec)) {
                break;
            }
        }
        if (KiteMapUtils.isEmpty(feeSpec)) {
            return;
        }
        List<Map<String, Object>> feeSpecAttrList = (List) KiteMapUtils.getObject(feeSpec, "productAttrs");
        if (KiteListUtils.isEmpty(feeSpecAttrList)) {
            return;
        }
        attrs.stream().forEach(kiteAttr ->{
            Map<String, Object> specAttr = feeSpecAttrList.stream().filter(feeSpecAttr -> KiteStringUtils.isEqual(kiteAttr.getCode(), KiteMapUtils.getString(feeSpecAttr, "attrCode"))).findFirst().orElse(null);
            if (KiteMapUtils.isNotEmpty(specAttr)) {
                kiteAttr.setValue(KiteMapUtils.getString(specAttr, "attrValCodes"));
            }

        });
    }

    private void dealAddRoleUserInstId(KitePosGoodsDTO goods, KitePosHandlerContext context) {
        // 附加产品，用户实例设置为主商品的用户实例
        if (KiteStringUtils.isNotEmpty(goods.getParentInstId())) {
            String userInstId = context.getPosDto().getGoods().stream().filter(goodsDTO ->
                KiteStringUtils.equals(goodsDTO.getInstanceId(), goods.getParentInstId())).findAny().map(KitePosGoodsDTO::getUserInstId).orElse("");
            goods.setUserInstId(userInstId);
        }
    }

    private boolean isDependence(String custId, String prodInstId, String funcProdId) {
        boolean result = false;
        KiteProdInst prodInst = querySceneInstService.getProdInst(custId, prodInstId);
        String offerId = ProductCache.get(prodInst.getProdId()).getBaseOfferId();
        List<OfferDetail> offerDetails = OfferCache.get(offerId).listAccessProdDetail();
        for (OfferDetail offerDetail : offerDetails) {
            String subOfferId = ProductCache.get(offerDetail.getObjId()).getBaseOfferId();
            if (KiteStringUtils.isEmpty(subOfferId) || KiteStringUtils.equals(subOfferId, offerId)) {
                continue;
            }
            OfferDetail detail = OfferCache.get(subOfferId).listMustDefaultFuncProdRstr(offerDetail.getObjId(), offerDetail.getRoleId()).stream()
                .filter(d -> KiteStringUtils.equals(d.getObjId(), funcProdId)).findFirst().orElse(null);
            if (Objects.nonNull(detail)) {
                result = true;
            }
        }
        return result;
    }

    /**
     * 返销时，所有新增的趸交资费失效时间刷新为操作前一天的23：59：59
     * @param fees
     * @param sceneInstId
     * @param resaleFeeList
     */
    private void dealResaleFeeAttrs(List<KitePosGoodsFeeDTO> fees, String sceneInstId, List<KitePosGoodsFeeDTO> resaleFeeList) {
        String sceneResale = querySceneInstService.getExtParameterValue(sceneInstId, "SCENE_RESALE");
        if (!KiteStringUtils.equals(sceneResale, "resale")) {
            return;
        }
        fees.stream().filter(f -> {
            String feeInstanceId = getFeeInstanceId(f);
            return resaleFeeList.stream().anyMatch(resaleFee -> KiteStringUtils.equals(getFeeInstanceId(resaleFee), feeInstanceId));
        }).forEach(fee -> {
            KitePosAttrDTO attr = fee.getAttrs().stream().filter(feeAttr ->
                KiteStringUtils.equals(feeAttr.getCode(), LocalKeyConsts.END_DATE_FIELD_NAME)).findFirst().orElse(null);
            if (Objects.nonNull(attr)) {
                attr.setValue(DateFormatUtils.getEndOfLastDay());
                if (!KiteStringUtils.equals(attr.getValue(), attr.getOriginValue())) {
                    attr.setChangeType(ChangeTypeUtils.CHANGE_TYPE_M);
                    // 资费属性变动，整个资费的状态也是修改
                    fee.setChangeType(ChangeTypeUtils.CHANGE_TYPE_M);
                }
            }
        });
    }

    /**
     * 返销订单新增的趸交资费
     * @param sceneInstId
     * @return
     */
    private List<KitePosGoodsFeeDTO> getResaleFeeList(String sceneInstId) {
        // 返销订单信息
        String resaleOrderId = querySceneInstService.getExtParameterValue(sceneInstId, "RESALE_ORDER_ID");
        KitePosDTO resalePosDTO = ResaleOrderInfoCache.get(resaleOrderId);
        // 获取到该订单新增的趸交资费
        return PaymentService.getOrderFee(resalePosDTO, ChangeTypeUtils.CHANGE_TYPE_A);
    }

    /**
     * 获取资费实例ID属性值
     * @param kitePosGoodsFeeDTO
     * @return
     */
    private static String getFeeInstanceId(KitePosGoodsFeeDTO kitePosGoodsFeeDTO) {
        return Optional.ofNullable(kitePosGoodsFeeDTO.getAttrs().stream().filter(s -> KiteStringUtils.equals(s.getCode(), "210004688"))
            .findFirst().orElse(null)).map(KitePosAttrDTO::getValue).orElse("");
    }

    /**
     * 五大双线收费方资费，设置资费收费单位属性值
     * @author zhang.song
     * @date 2022-02-08 21:42
     * @param prodAttrMap
     * @param chargeCity
     * @return java.util.Map<java.lang.String,com.iwhalecloud.bss.kite.manager.inst.KiteAttr>
     */
    private static Map<String, KiteAttr> setFeeChargeUnit(Map<String, KiteAttr> prodAttrMap, String chargeCity) {
        if(KiteStringUtils.isEmpty(chargeCity) || Objects.isNull(prodAttrMap) || prodAttrMap.isEmpty()) {
            return prodAttrMap;
        }

        KiteAttr kiteAttr = prodAttrMap.get("210005009");
        if(Objects.nonNull(kiteAttr)) {
            kiteAttr.setValue(chargeCity);
            kiteAttr.setValueDesc(chargeCity);
        }
        return prodAttrMap;
    }

    /**
     * 从产品属性获取收费地市值（资费属性-收费单位需要传收费地市）
     * @author zhang.song
     * @date 2022-02-09 17:21
     * @param goods
     * @param offerInst
     * @return java.lang.String
     */
    private static String getChargeCityFromProductAttr(KitePosGoodsDTO goods, KiteOfferInst offerInst) {
        // 五大双线基础产品
        if(ProdCateUtil.getDoubleLineOfferId().contains(offerInst.getOfferId())) {
            List<KitePosProductDTO> products = goods.getProducts();
            if(KiteListUtils.isNotEmpty(products)) {
                for (KitePosProductDTO product : products) {
                    List<KitePosAttrDTO> attrs = product.getAttrs();
                    if(KiteListUtils.isNotEmpty(attrs)) {
                        String chargeCity = attrs.stream().filter(attr ->
                            KiteStringUtils.isEqual(attr.getCode(), "210008008")).findAny().map(KitePosAttrDTO::getValue).orElse(null);
                        if(KiteStringUtils.isNotEmpty(chargeCity)) {
                            return chargeCity;
                        }
                    }
                }
            }
        }
        return null;
    }
}
